Cannot get MaxHeapify to work properly - java

Well, I have spent over 8 hours working on this. I have copied the example from the book verbatim, as well as trying to implement the heap based on other resources online. I still cannot get the heap to work right. Here is what I have coded so far:
import static java.lang.System.*;
import java.util.Random;
import java.util.Scanner;
public class Heap{
static int[] arr;
static int heapSize;
static int max = 0;
public static void main(String[] args) {
Scanner keys = new Scanner(in);
out.print("Enter size of heap desired: "); //Receive input from user regarding
int arrSize = keys.nextInt(); //desired heap size
ArrayBuild(arrSize); //Call builder to construct array based on user desired size
heapSize = arr.length;
int start = arr.length/2-1;
MaxHeapify(start);
keys.close();
}
public static void ArrayBuild(int size){ //Constructs new array based on given size
arr = new int[size];
for(int i=0; i<arr.length; i++)
arr[i] = new Random().nextInt(10)+1;
}
public static void MaxHeapify(int i){
int left = 2*i;
int right = 2*i+1;
if(left <= heapSize && arr[left] > arr[i]){
max = left;
}else{
max = i;
}
if(right <= heapSize && arr[right] > arr[max]){
max = right;
}
if(max != i){
swap(i, max);
MaxHeapify(max);
}
}
public static void BuildMaxHeap(){
for(int i=(arr.length/2); i>0; i--)
MaxHeapify(i);
}
public static void swap(int i, int max){
int temp = arr[i];
arr[i] = arr[max];
arr[max] = temp;
}
}

2 problems:
int left = 2 * i;
int right = 2 * i + 1;
Should be:
int left = 2 * i + 1;
int right = 2 * i + 2;
Java arrays are 0 based so for the root (which is the first element) with your formula is for cases when you use a 1 based array. In Java the left child would be also 0 as 2*0=0 from what I remember etc.
Second when you are building the heap in main() you need to run MaxHeapify() for half of the elements like you're doing in BuildMaxHeap(), not only for the middle one, like this:
for(int start = arr.length / 2 - 1; start >= 0; start--) {
MaxHeapify(start);
}
Also in BuildMaxHeap() you should change the stop condition to >= and start at arr.length / 2 - 1.
Hope this helps.

Related

Garbage Value Picked Up by Scanner -- Java [duplicate]

This question already has answers here:
What's the simplest way to print a Java array?
(37 answers)
Closed 3 months ago.
I am trying to sort an array in descending order. The size of the array comes from user input, and then the contents of the array come from user input. Then the array is passed to a function that sorts it. The issue is that, instead of printing a sorted array, it prints [I#5caf905d. Through print statements, I have pinpointed the problem to the scanner picking up [I#5caf905d as the final value from user input, coming right after all the correct inputs. I don't know where this value came from, and I also don't understand why it is printed by the function as if it were the entire array. All help is appreciated!
Here is my code. Input is: 5 10 4 39 12 2.
import java.util.Scanner;
public class LabProgram
{
public static void sortArray (int [] myArr, int arrSize)
{
int temp;
int i;
for (i = 0; i < arrSize - 1; i++)
{
if (myArr[i] < myArr[i + 1])
{
temp = myArr[i];
myArr[i] = myArr[i + 1];
myArr[i + 1] = temp;
}
}
System.out.println(myArr);
}
public static void main(String[] args)
{
Scanner scnr = new Scanner (System.in);
int [] myArr;
int arrSize;
int i;
arrSize = scnr.nextInt();
myArr = new int[arrSize];
for (i = 0; i < arrSize; i++)
myArr[i] = scnr.nextInt();
sortArray (myArr, arrSize);
}
}
You should use one of the simpliest sorting algorithm e.g. Selection Sort:
public static void selectionSortDesc(int[] arr) {
for(int i = 0; i < arr.length; i++) {
// k index with max value
int k = i;
// find k with max value
for(int j = i; j < arr.length; j++) {
if(arr[k] < arr[j])
k = j;
}
// swap current element with the max value
swap(arr, i, k);
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = arr[i];
}
By the way, you should not mix sorting and printing the array. It's better to split these parts.

how to construct an array of 100 elements containing the numbers 1 -100 for which shellsort, with the increments 1 4 13 40 (The worst case)?

This is the original question
"Shell Sort worst case. Construct an array of 100 elements containing the numbers 1 through 100 for which shellsort, with the increments 1 4 13 40, uses as large a number of compares as you can find."
There are 100! permutations for an array of 100 elements, it's terrifying to go through each permutation and find which one has the maximum number of compares. Is there any smarter way to approach this problem? My approach this problem is through violence, but only randomly shuffle the array 100000000 time which is less than 100! and it take me half an hour to get the final output.
I pasted my code below. I appreciate any suggestions from you guys!
`
package ch_2_1;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import java.util.Arrays;
public class exer_19
{
public static void main(String[] args)
{
// initial permutation
int[] array = new int[100];
for ( int i = 1; i < 101; i++)
{
array[i-1] = i;
}
// find the worst case and the number of compares
worst_input(array);
}
private static void worst_input(int[] array)
{
int max_count = 0;
int[] copy = new int[100];
int[] worst_case = new int[100];
for ( int i = 0; i < 100000000; i++)
{
int[] temp = generate(array);
for (int j = 0; j < 100; j++){ copy[j] = temp[j];}
Shell_sort operation = new Shell_sort();
operation.shell_sort(temp);
if (operation.compare() > max_count)
{
max_count = operation.compare();
worst_case = copy;
}
System.out.println(i);
}
for ( int s : worst_case){ System.out.print(s + " ");}
System.out.println();
System.out.println(max_count);
System.out.println();
}
private static int[] generate( int[] array)
{
StdRandom.shuffle(array);
return array;
}
private static class Shell_sort // it's necessary to create a private class to hold the shell sort method
// b/c the method must record the # of compares to sort the array, and this # count need to be returned
// to the worst_input method. Therefore, having a class to encapsulate the two methods is very helpful
{
private int count = 0;
private void shell_sort(int[] test)
{
int N = test.length;
int h = 1;
while (h < N/3) h = 3*h + 1; // 1, 4, 13, 40, 121...
while ( h > 0)
{
for ( int i = h; i < N; i++) // starting from the largest h-value th element of the array (simplified: ith element)
{
// if ith element is less than i-h th element, swap the two, continue this process until the condition is not met
for ( int j = i; j >= h && less( test[j], test[j-h]); j = j - h)
{
exchange( test, j, j-h);
count++;
}
}
// when reached the end of the array, update h value
h = h/3;
}
}
private int compare()
{
return count;
}
}
private static boolean less( int current, int previous)
{
return current < previous;
}
private static void exchange(int[] array, int cur_index, int pre_index)
{
int temp = array[pre_index];
array[pre_index] = array[cur_index];
array[cur_index] = temp;
}
}
`

Quickselect that runs in O(n) in Java?

So I'm implement a quickselect algorithm that chooses a good pivot each time. What it does is divide the array into groups of 5, sorts each groups and finds the median. It then takes the medians of each group, groups those values up and then finds the median of medians. Here's what I have:
private static int pickCleverPivot(int left, int right, int[] A){
int index = 0;
int n = right-left;
if (n <= 5) {
Arrays.sort(A);
index = n/2;
return index;
}
int numofMedians = (int) Math.ceil(n/5);
int[] medians = new int[numofMedians];
int[] groups = new int[5];
for(int i = 0; i < numofMedians; i++) {
if (i != numofMedians - 1){
for (int j = 0; j < 5; j++){
groups[j] = A[(i*5)+j];
}
medians[i] = findMedian(groups, 5);
} else {
int numOfRemainders = n % 5;
int[] remainder = new int[numOfRemainders];
for (int j = 0; j < numOfRemainders; j++){
remainder[j] = A[(i*5)+j];
}
medians[i] = findMedian(groups, 5);
}
}
return pickCleverPivot(left, left+(numofMedians), medians);
}
public static int findMedian(int[] A, int n){
Arrays.sort(A);
if (n % 2 == 0) {
return (A[n/2] + A[n/2 - 1]) / 2;
}
return A[n/2];
}
private static int partition(int left, int right, int[] array, int pIndex){
//move pivot to last index of the array
swap(array,pIndex,right);
int p=array[right];
int l=left;
int r=right-1;
while(l<=r){
while(l<=r && array[l]<=p){
l++;
}
while(l<=r && array[r]>=p){
r--;
}
if (l<r){
swap(array,l,r);
}
}
swap(array,l,right);
return l;
}
private static void swap(int[]array, int a, int b){
int tmp = array[a];
array[a] = array[b];
array[b] = tmp;
}
So it works like it's supposed to but now I'm wondering if it's possible to get it to run in linear O(n) time. I'm currently comparing this code to just choosing a random pivot. On smaller arrays this code runs faster but on larger arrays, choosing a random pivot is faster. So is it actually possible to make this run in O(n) time or is that just in theory and if it's not possible for it to run that fast then is this method running as fast as it could.

Getting error in implementation of heap sort

I'm trying to create and sort a heap using this array in Java. I keep getting
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 42
at HeapSort.exchange(HeapSort.java:28)
at HeapSort.Max_Heapify(HeapSort.java:22)
at HeapSort.Build_Heap at HeapSort.Sort(HeapSort.java:36)
at HeapSort.main(HeapSort.java:46)
I'm not sure where the error is coming from.
public class HeapSort {
public static int n;
public static int[] a;
public static int largest;
public static void Build_Heap(int[] a){
n = a.length-1;
for(int i = n/2; i >= 0; i--){
Max_Heapify(a,i);
}
}
public static void Max_Heapify(int[] a,int i){
int left = 2*i;
int right = 2*i +1;
if(left <= n && a[left] > a[i])
largest = left;
if(right <=n && a[right] > a[largest])
largest = right;
if(largest != i)
exchange (a[i],a[largest]);
Max_Heapify(a,largest);
}
private static void exchange(int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
// TODO Auto-generated method stub
}
public static void Sort(int[] a0){
a = a0;
Build_Heap(a);
for(int i = n; i > 0; i--){
exchange(0,i);
n = n-1;
Max_Heapify(a,0);
}
}
public static void main(String[] args){
int[] a1 = {3,55,6,42,34,56,34};
Sort(a1);
for(int i = 0; i < a1.length; i++){
System.out.print(a1[i] + " ");
}
}
}
You are getting an error in exchange(). The parameters i and j for that method look like to be indexes of the array a. But, you are calling the method exchange(a[i],a[largest]) which is passing the value of from the array at indexes i and largest instead of passing the actual indexes i and largest to the method.
Try calling exchange like exchange(i,largest)
The exchange call (on line 22) in Max_Heapify() is given the values of the array at those locations instead of the locations (the indexes, i and largest) that can be anything, in this example, 42 which is larger than the array to be sorted length,

QuickSort with Random and median

I am working on an assignment with QuickSort to show how fast the algorithm when using different methods for getting the Pivot like random or median of three. so far when using random or median I get different outputs and none of them is sorted, I couldn't figure out what my mistakes are. I went every where on the internet. Can someone looks at it and tell me what I'm doing wrong here?
Here is the QuickSort code:
import java.util.*;
public class QuickSort {
public static void main(String[] args) {
int[] arr = {5, -32, 12, 43, 88, 19, 113, 62, -11, 2};
System.out.println(Arrays.toString(arr));
quickSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr) {
quickSort1(arr, 0, arr.length -1);
}
private static void quickSort1(int[] list, int first, int last) {
if (first < last) {
int pivotLocation = partition(list, first, last);
quickSort1(list, first, pivotLocation - 1);
quickSort1(list, pivotLocation + 1, last);
}
}
private static int partition(int[] list, int first, int last) {
int pivot;
int smallIndex;
Random rand = new Random();
int num = rand.nextInt(list.length);
swap(list, first, (first + last) / 2);
pivot = list[first];
//pivot = medianOfThree(list, first, last);
//pivot = list[num];
smallIndex = first;
for (int index = first + 1; index <= last; index++) {
if (list[index] < pivot) {
smallIndex++;
swap(list, smallIndex, index); // Should we limit to if(smallIndex != index)
}
}
swap(list, first, smallIndex);
return smallIndex;
}
private static void swap(int[] list, int first, int second) {
int temp;
temp = list[first];
list[first] = list[second];
list[second] = temp;
}
private static int medianOfThree(int[] arr, int first, int last) {
int f = arr[first], l = arr[last], m = arr[(last + first)/2];
if(l <= f && l >= m || l >= f && l <= m)
return l;
else if (m <= f && m >= l || m >= f && m <= l)
return m;
return f;
}
}
I tried using while() it was faster but I have to test the speed of the sort with looping 100+ times which gave mejava.lang.StackOverflowError.
Any piece of advice will be helpful.
Edit:
I have fixed the median method and the random, thanks for the help.
I was working on the while loop and I figured how to make it work and sort properly. The problem now is, whenever I try to make large array to test the speed of the sorting it gets stack and I'm not sure (by large I mean 10,000 elements).
I call the class from another program but it's still not working as expected.
here is the partition method, the class is the same:
private static int partition(int[] list, int first, int last) {
Random rand = new Random();
int pivot = 0;
int num = first + rand.nextInt(last - first + 1);// generates random index
pivot = medianOfThree(list, first, last); //finding median of three numbers
//pivot = list[first]; //using the first data as pivot
//pivot = list[num]; //Random index value is used as pivot
int leftPointer= first ;
int rightPointer = last ;
//swap(list, last, (first+last)/2);
while(true) {
while (list[leftPointer] < pivot)
leftPointer++;
while (rightPointer > 0 && list[rightPointer] > pivot)
rightPointer--;
if(leftPointer >=rightPointer)
break;
swap(list, leftPointer, rightPointer);
//count++;
//System.out.println(Arrays.toString(list)+ "switch"+ count );
}
//System.out.println(Arrays.toString(list));
//swap(list, last, leftPointer);
//System.out.println(leftPointer);
return leftPointer;
}
Edit:
this is the Test code I'm using to test sorting efficiency and the QuickSort using whileloop is still not working as it should, am I doing something wrong?
Test code:
import java.util.*;
public class Test {
public static final int ARRAYSIZE = 50000; // Test array element count
public static final int ELEMENTSIZE = 10000; // Test array element size
public static final int LOOPS = 1000;
public static void main(String[] args) {
long t1=0,t2=0,t3=0;
long c1=0,c2=0; // Counters
for(int test = 1; test <= LOOPS; test++) {
System.out.print(test + "..");
Random rand = new Random();
int[] arr1 = new int[ARRAYSIZE];
for(int i = 0; i < ARRAYSIZE; i++) // Generate a random array with ARRAYSIZE elements
arr1[i] = rand.nextInt(ELEMENTSIZE);
int[] arr2 = Arrays.copyOf(arr1, arr1.length); // Use an exact array copy for each sorting test
int[] arr3 = Arrays.copyOf(arr1, arr1.length);
t1 = System.currentTimeMillis();
QuickSort.quickSort(arr1); //Run & Time Quick Sort
t2 = System.currentTimeMillis();
Arrays.sort(arr3); //Run & Time Arrays.sort
t3 = System.currentTimeMillis();
c1 += t2-t1;
c2+=t3-t2;
}
System.out.println();
System.out.println("Quick Sort took: " + c1/LOOPS + " milliseconds");
System.out.println("Arrays.sort took: " + c2/LOOPS + " milliseconds");
}
/* ADD YOUR CODE HERE */
}
I spotted at least two mistakes, there are probably others. For the selection of a random element you should use something like:
int num = first + rand.nextInt(last - first + 1);
For the median of three the middle element is:
int m = arr[(last + first)/2];
I suggest you run the program with a debugger and convince yourself after each step that the correct thing was done.
I have found the problem with the code, Whenever it compare the exact same Value, it keeps switching and compare them again... so I made a condition to break the loop whenever that occurs.
I used :
if(leftPointer >=rightPointer || list[leftPointer]== list[rightPointer])
break;
else
swap(list, leftPointer, rightPointer);
instead of:
if(leftPointer >=rightPointer)
break;
else
swap(list, leftPointer, rightPointer);
The sort works fine.
-Thanks

Categories