Getting error in implementation of heap sort - java

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,

Related

Recursive Selection Sort in Java

I need to implement this algorithm creating a new ArrayList object at each recursive call.
My starting Array contains integers in this order"20, 40 ,10, 30 ,50 ,5" , after sorting it I have 5,5,5,5,5,5. I think that the problem is in the recursive call and in the last for cicle of the SelectionSort because removing the last for I notice that the the first element is sorted correctly.
import java.util.*;
public class SelectionSort {
//var
public ArrayList<Integer> arr ;
//constructor
public SelectionSort(ArrayList<Integer> arr){
this.arr = arr;
}
public ArrayList<Integer> getarraylist() {
return arr;
}
public void sort(){
//position of the last sorted element
int minimum =0;
if (arr.size() <=0 ) return;
for ( int j = 1; j < arr.size()-1; j++ ) {
if (arr.get(j) < arr.get(0) ) {
minimum = j;
//swap element 0 and minimum
int temp = arr.get(0);
arr.set(0, arr.get(minimum));
arr.set(minimum, temp);
}
}
//recursive call, new array without first element (already sorted)
ArrayList<Integer> arr2 = new ArrayList<>(arr.subList(1,arr.size()));
SelectionSort s2 = new SelectionSort(arr2);
s2.sort();
for(int i=0;i<s2.getarraylist().size();i++) {
arr.set(i, s2.getarraylist().get(i));
}
}
Driver class
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<Integer (Arrays.asList(20,40,10,30,50,5));
System.out.println("\n ARRAY ELEMENTS \n ");
for (int i: arr) {
System.out.println(i);
}
System.out.println("\n SORTED ELEMENTS \n ");
SelectionSort s = new SelectionSort(arr);
s.sort();
for (int i: s.getarraylist()) {
System.out.println(i);
}
}
}
You have actually two bugs in your algorithm that, together, lead to the observed output.
The first bug is within the for-loop that determines the minimal element:
for ( int j = 1; j < arr.size()-1; j++ ) { ...
You terminate one element too early, i.e. the last element is never considered. Thus, after the first iteration, the 5 is the last element in your ArrayList. In fact, it is the last element in every of your ArrayLists. The fix is to not subtract 1 in the for-condition:
for ( int j = 1; j < arr.size(); j++ ) { ...
The second bug is in your last for-loop where you copy the values from index i of s2 to index i of arr. You neglect the fact that s2 is one element shorter than arr. Thus, the only element not overriden is the last element. The fix is to get the i-th element from s2, but write it at the i + 1-th index of arr:
arr.set(i + 1, s2.getarraylist().get(i));
Now let us take look at how those two bugs lead to the observed output. Since
the last element in your ArrayList is never overridden and
the last element is always the same,
all elements have the same value (in your test case: 5).
Some remarks on your code:
the variable minimum is superfluous and can be replaced with j.
If you replace all occurences of ArrayList in SelectionSort with List, you can actually simplify the last part of your code to:
// remove the line declaring arr2, it is no longer needed
SelectionSort s2 = new SelectionSort(arr.subList(1, arr.size()));
s2.sort();
// last for-loop not needed anymore, method ends here
This is possible because ArrayList#subList(...) states that "The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa."
You should take a little bit more care wrt. indentation.
You have some minor inconsistencies in your coding style. For example, sometimes you write a blank after ( or before a ) or {, sometimes you do not. See what you like more and use it uniformly.
In Java, variable-, parameter- and methodnames should be written in camelCase (getarraylist() -> getArrayList())
With your last loop:
for(int i=0;i<s2.getarraylist().size();i++) {
arr.set(i, s2.getarraylist().get(i));
}
This overrides every element with the same number. (Why you got all 5's as your result) This is because you only iterate to the second to last element (arr.size()-1). Then you copy the elements in the line:
ArrayList<Integer> arr2 = new ArrayList<>(arr.subList(1,arr.size()));
Eventually you are only copying the last element over (5) and then copying this to the final ArrayList arr.
Also you create another SelectionSort object every time you call the sort method. This is not good.
Here is the code I wrote:
public void sort(List<Integer> list){
//position of the last ordered element
int minimum =0;
if (list.size() <=0 ) return;
for ( int j = 1; j < list.size(); j++ ) {
if (list.get(j) < list.get(0) ) {
minimum = j;
//swap element 0 and minimum
int temp = list.get(0);
list.set(0, list.get(minimum));
list.set(minimum, temp);
}
}
sort(list.subList(1,list.size()));
}
I changed it to accept an argument of List<Integer> (Because the subList() method returns a List) and then got rid of the last loop and where you created new objects.
Also youll have to change
s.sort();
to:
s.sort(s.getarraylist());
Output:
ARRAY ELEMENTS
20
40
10
30
50
5
SORTED ELEMENTS
5
10
20
30
40
50
Im not sure I understand the question, but I created a recursive (and iterative) selectionSort and InsertionSort just for fun, hope it helps.
public class Sorts {
public static void swap(Comparable[] a, int i, int j) {
Comparable temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void selectionSortItr(Comparable[] a, int n) {
for (int i = 0; i < n - 1; i++) {
int f = i;
for (int j = i + 1; j < n; j++) {
if (a[j].compareTo(a[f]) < 0)
f = j;
}
swap(a, i, f);
}
}
public static int select(Comparable[] a, int n, int j, int f) {
if (j >= n)
return f;
if (a[j].compareTo(a[f]) < 0)
f = j;
return select(a, n, j + 1, f);
}
public static void selectionSort(Comparable[] a, int n, int i) {
if (i < n - 1) {
swap(a, i, select(a, n, i + 1, i));
selectionSort(a, n, i + 1);
}
}
public static void insertionSortItr(Comparable[] a) {
for (int i = 1; i < a.length; i++) {
int j;
Comparable cur = a[i];
for (j = i; j > 0 && cur.compareTo(a[j - 1]) < 0; j--) {
a[j] = a[j - 1];
}
a[j] = cur;
}
}
public static void insertionSortInner(Comparable[] a, Comparable cur, int j) {
if (j > 0 && cur.compareTo(a[j - 1]) < 0) {
a[j] = a[j - 1];
insertionSortInner(a, cur, j - 1);
} else {
a[j] = cur;
}
}
public static void insertionSort(Comparable[] a, int i, int n) {
if (i < n) {
insertionSortInner(a, a[i], i);
insertionSort(a, i + 1, n);
}
}
public static void main(String[] args) {
Integer[] a = new Integer[10];
for (int i = 0; i < 10; i++)
a[i] = (int) (Math.random()*100);
selectionSort(a, 10, 0);
for (int i = 0; i < 10; i++)
System.out.println(a[i]);
}
}

Returning an array in Heap's recursive algorithm

I've implemented the Heap's algorithm for finding all permutations of the elements of array A:
//A = {1, 2, 3, 4}; B = perms(A) ; num_row(B) = (4!+1) and B[0][0] = 4!;
//This is B.R. Heap's algorithm
public static void perms(int [] A, int [][]B, int n)
{
if (n == 1)
{
int k = B[0][0];
for (int i = 0; i < A.length; i++)
{
B[k + 1][i] = A[i];
}
B[0][0]++;
}
else
{
for (int i = 0; i < n - 1 ;i++)
{
perms(A, B, n-1);
if (n % 2 == 0)
{
swap(A, i, n - 1);
}
else
{
swap(A, 0, n - 1);
}
}
perms(A, B, n - 1);
}
}
public static void swap(int[] A, int i, int j)
{
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
I'm new to Java. The problem is I want to have B as the output (return) of the function perms(A) , but in this implementation, I have to initialize a int[n! + 1][A.length] B array before calling the function. How can I do it?
Is there anything like private variable or anything in java to help a recursive function to remember a variable from a former call?
Thanks
You can create an "entering" method to recursion like this:
public static int[][] perms(int[] a){
int[][] perms = new int[factorial(a.length)+1][a.length];
perms(a,perms,a.length);
return perms;
}
Method factorial is well know method and can be found on Google for example
Wondering if n parameter is neccessary
EDIT
it is not neccessary (above corrected)
EDIT
By my test the k variable is just incrementing, so I would use static variable like this:
private static int counter = 0;
// your code here, following is a part of your perms method
if (n == 1)
{
for (int i = 0; i < A.length; i++)
{
B[counter][i] = A[i];
}
counter++;
}
//and my code corrected too:
public static int[][] perms(int[] a){
int[][] perms = new int[factorial(a.length)][a.length]; //+1 is not necessary
counter=0; //necessary to call it again
perms(a,perms,a.length);
return perms;
}

How use other written methods with present method

I wrote a program for this problem:
“Write a program that, given an array array[] of n numbers and another number x, determines whether or not there exist two elements in array whose sum is exactly x.”
Which is this:
boolean hasArrayTwoCandidates (int array[], int sum) {
int length = array.length;
quickSort(array, 0, length-1);
int first, last;
first = 0;
last = length-1;
while(first < last){
if( array[first] + array[last] == sum )
return true;
else if( array[first] + array[last] < sum )
first++;
else // array[i] + array[j] > sum
last--;
}
return false;
}
At first place, I don't know where should I put or add "quick sort" codes. I have this problem with other programs, as well; when I want to add written methods to the present one.
Should I create a "new class" under this "project" and put "quicksort" codes there?
Should I put them in this class? but how can I use it?
At second place, I don't know what should I write in my "main method"?
this is my quicksort codes:
public void sort(int[] values) {
if (values == null || values.length == 0){
return;
}
this.array = values;
length = values.length;
quickSort(this.array, 0, length - 1);
}
private void quickSort(int[] array, int low, int high) {
int i = low, j = high;
int pivot = array[low + (high-low)/2];
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchange(i, j);
i++;
j--;
}
}
if (low < j)
quickSort(array, low, j);
if (i < high)
quickSort(array, i, high);
}
private void exchange(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
actually, I dont know what should I write in my "main method" to run this program?
For you Question you can do simply this kind of coding in main method:
public static void main(String[]args) {
int x = 20;
int[] arr = {2,5,4,10,12,5};
System.out.println(hasArrayTwoCandidates(arr,x));
}
make the methods static
static boolean hasArrayTwoCandidates (int array[], int sum)
But there are porblems in your coding:
private void exchange(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
Here the array is not defined. you'll get an error. you have to pass the array too to the method make it as.
private void exchange(int i, int j,int[] array)
But since you are not necessary to do sorting. I recommend this.
static boolean hasArrayTwoCandidates (int array[], int sum) {
boolean flag = false;
for(int i=0;i<array.length-1;i++){
for(int j=i+1;j<array.length ;j++){
if(array[i]+array[j] == sum)
flag = true;
}
}
return flag;
}
this will get one element and check while adding other elements that it is true
Then the main method come same way.
you can put all those method in same class, make hasArrayTwoCandidates() static (Note that main method is static and a static method can have access only to static methods)
public static boolean hasArrayTwoCandidates (int array[], int sum) {
....
}
and in your main method you can test it like this :
public static void main(String[] args){
int[] arr = {2,5,12,5,2,7,15};
System.out.print(hasArrayTwoCandidates(arr, 27));
}
Answering your questions: you can write methods and call them within the same class, just write them with the static modifier:
private static <return_type> <methodName> (<type> param1, <type> param2) {
// Your code here
}
For a program like this, I don't get why you are thinking about sorting the array before checking the sum of 2 numbers within it, when you could do all at once. Check out this code, this may shine a light on you. It is straight-forward and only to see if it clarifies your logic.
import java.util.Random;
public class VerifySum {
public static void main(String[] args) {
Random rand = new Random();
int[] array = new int[10];
// Produce a random number from 10 to 20
int randomSum = rand.nextInt(11) + 10;
// Fill out the array with random integers from 0 to 10
for (int i = 0; i < array.length; i++) {
array[i] = rand.nextInt(11);
}
// Check all array indexes against each other
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] + array[j] == randomSum) {
System.out.println(array[i] + " + " + array[j] + " = " + randomSum);
}
}
}
// Print "x"
System.out.println("randomSum = " + randomSum);
// Print array for verification of the functionality
for (int i = 0; i < array.length; i++) {
System.out.println("array [" + i + "] = " + array[i]);
}
}
}
Sometimes making it simpler is more efficient. ;-)

Cannot get MaxHeapify to work properly

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.

Selection Sort in Java, ways I can improve the code?

This is the code I have for my selection sort program, I want to know if there's any way of improving the code without using additional methods or classes.
public class Selection_Sort {
public static void main(String[] args) {
int arr[]={234,151,123,4,5342,76,48};
int min=0; int temp;
for(int i=0;i<=arr.length-1;i++){
min=i;
for (int k=i+1;k<arr.length;k++){
if(arr[k]<arr[i]){
temp=arr[i];
arr[i]=arr[k];
arr[k]=temp;
}
}
}
for (int j=0;j<=arr.length-1;j++)
System.out.println(arr[j]+" ");
}
}
public static void main(String[] args) {
int arr[]={234,151,123,4,5342,76,48};
int arrLength = arr.length;
for(int i=0;i<arrLength-1;i++){
int min=i;
for (int k=i+1;k<arrLength;k++){
if(arr[k]<arr[min]){
min = k;
}
}
if (i != min) {
int temp=arr[i];
arr[i]=arr[min];
arr[min]=temp;
}
}
for (int j=0;j<arrLength;j++) {
System.out.println(arr[j]+" ");
}
}
Looks like you are using the bubblesort algorithm which is very slow. If you want to improve your code, i would recommend to use an algorithm like ripplesort or quicksort.
Slight improvement should be like this :
int arrayLength = arr.length;
// Then use it in conditional statement of for loop.
So that it won't invoke length property of Array every time in loop. For small number of loops it doesn't impact much but it will help to reduce the time when loops are more or number of iteration of loop are more.
The value of the local variable min is not used
k <= arr.length-1
-->
k < arr.length
Use this
class Selection {
public static void main(String[] args) {
int arr[]={234,151,123,4,5342,76,48}; /* arr[0] to arr[n-1] is the array to sort */
int lowest, i, j;
for(i = 0 ; i < arr.length-1; i++) { /* advance the position through the entire array */
lowest = i; /* assume the min is the first element */
for(j = i+1 ; j < arr.length; j++) { /* if this element is less, then it is the new minimum */
if(arr[j] < arr[lowest]) {
lowest = j; /* found new minimum; remember its index */
}
}
if(lowest != i) { /* lowest is the index of the minimum element. Swap it with the current position */
int temp = arr[i];
arr[i] = arr[lowest];
arr[lowest] = temp;
}
}
for (int k = 0; k <= arr.length-1 ; k++) {
System.out.println(arr[k] + " ");
}
}
}
This is the selection sort algorithm you asked.
Here is original Selection sort implementation. The implementation in question in not using min to perform the swap operation.
public static void sort(int[] arr) {
int min=-1;
for (int i = 0; i < arr.length; i++) {
min = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if (min != i) {
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
}
public class JavaApplication55 {
public static void main(String[] args) {
int[] array ={234,435,567,768,123,456,789,789,5670,6789};
for(int j =0;j< array.length;j++){
for(int i =j+1;i < array.length;i++ ){
int temp;
if(array[j]>array[i]){
temp =array[j];
array[j] =array[i];
array[i] =temp;
}
else{}
}}
for(int k =0;k< array.length;k++){
System.out.println(array[k]);
}
}
enter code here
}

Categories