Java's .sort() method breaks the while loop - java

Recently started learning Java and during implementing the "binary search" found out that if I call the Arrays.sort() on the array I am about to search in, it makes the loop to be infinite. Removing/commenting out the line solves the problem, but I cannot get why. My intension is to pass the sorted array to the .binarySearch() method. Tried to figure out with debugger but could not. Don't want to leave this question without the answer, can anyone, please, help?
import java.util.Arrays;
public class Main {
static class BinarySearch {
int binarySearch(int[] array, int value) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + high / 2;
int guess = array[mid];
if (guess == value) {
return mid;
} else if (guess > value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
}
public static void main(String[] args) {
BinarySearch bs = new BinarySearch();
int[] a = {1, 3, 4, 45, 54, 666, 2, 4};
Arrays.sort(a);
int result = bs.binarySearch(a, 45);
if (result == -1) {
System.out.println("value not found");
} else {
System.out.println("value found at position: " + result);
}
}
}

Arrays.sort doesn't really have anything to do with you ending up with an infinite loop. It's the way you calculate mid.
Should've been (low + high) / 2. You seem to have forgot to add parentheses.

Related

Merge sort recursion trouble

I've been trying to make a merge sort and I got the merging part down, it's just the recursive splitting that I'm having a little trouble with. The left and right lists are getting merged and sorted individually and not carrying over between each recursive pass. I'm not sure what I'm doing wrong with the recursion or how to fix it without scrapping the entire division method.
public static int[] mergeSort(int[] x)
{
divide(x);
return sorted;
}
public static void divide(int[] x)
{
int midP;
if((x.length/2f) == 1.5f) //the left side of the list will always be larger
midP = 2;
else
midP = x.length/2;
if(midP == 0) //if the list contains one number end
return;
System.out.println("mid: " + midP);
int[] left = new int[midP];
int[] right = new int[x.length - midP];
for(int i = 0; i < midP; i++) //fills the left list
left[i] = x[i];
for(int i = midP; i < x.length; i++) //fills the right list
right[i-midP] = x[i];
divide(left);
divide(right);
sorted = merge(left, right);
}
public static int[] merge(int[] x, int[] y)
{
int[] mergedList = new int[x.length + y.length];
int counter = 0, xCounter = 0, yCounter = 0, high = 0;
while(xCounter < x.length && yCounter < y.length)
{
printArray(x);
printArray(y);
System.out.println("checking: " + x[xCounter] + " " + y[yCounter]);
if(x[xCounter] < y[yCounter])
{
mergedList[counter] = x[xCounter];
high = y[yCounter];
if(xCounter != x.length)
xCounter++;
}
else
{
mergedList[counter] = y[yCounter];
high = x[xCounter];
if(yCounter != y.length)
yCounter++;
}
counter++;
}
mergedList[counter] = high;
return mergedList;
}
public static void printArray(int[] x)
{
System.out.print("list: ");
for(int i = 0; i < x.length; i++)
System.out.print(x[i] + " ");
System.out.println();
}
When using recursive methods, it's tricky to use static or instance variables like sorted in this case. What's happening is that sorted gets set and reset over the recursive calls, and it can be difficult to predict what its value will be at any given time. Recursive functions are easier to understand if you only use local variables. So change your divide function so that it returns the sorted array, and use the return value from the recursive calls:
public static int[] divide(int[] x) {
... your existing divide logic ...
int[] leftSorted = divide(left);
int[] rightSorted = divide(right);
return merge(leftSorted, rightSorted);
}
Don't forget to also change the main entry point:
public static int[] mergeSort(int[] x) {
return divide(x);
}
You seem to still have a bug in the merge method:
int[] x = {5, 4, 1, 2, 3};
int[] sorted = mergeSort(x);
results in 1 2 3 4 0

label doesn't work, I tried my best

I tried continue & break labels in java but it throw errors.
Here is the code:
private int search(int[] seq, int key, int low, int high){
int mid = low + (high - low) / 2;
out : //label
if (key == mid) {
return mid;
}
if (key < mid) {
high = mid;
if (key != mid) {
break out;
}
}
return 1;
}
Labels are to be used with loops if you have 3 loops and you need to call break; in the innermost loop, you would then use a label to break to the outer loop because if you just call break; it will break the innermost and go to the middle loop. Your using the label wrong and you could easilly solve your problem by using either if .. if else and else statements or use the switch statement.
Labelled break works only with cycles.
And beware, they are not equivalent with goto because they transfer the control to the next statement after the break-ed cycle.
Here an example copied from the language basics tutorial - break statement on Oracle's site (I'm too lazy to be original if other good examples are available):
public static void main(String[] args) {
int[][] arrayOfInts = {
{ 32, 87, 3, 589 },
{ 12, 1076, 2000, 8 },
{ 622, 127, 77, 955 }
};
int searchfor = 12;
int i;
int j = 0;
boolean foundIt = false;
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length;j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search;
}
}
}
if (foundIt) // etc
}
}
Just in case you are interested more on how to solve the binary search than how to use breaking to labels. The code below has the same performance as one that would use goto's (if they'd actually exist in java).
private static int search(int[] seq, int key, int low, int high) {
while (low <= high) {
// this is as good as low+(high-low)/2.
int mid = (low + high) >>> 1; // this is (low+high)/2
int midVal = seq[mid];
if (midVal < key) {
low = mid + 1;
}
else if (midVal > key) {
high = mid - 1;
}
else {
// why break when you can return?
return mid; // key found
}
}
// key not found. Return the 2's complement of the insert position:
// that is -(insertPosition+1)
return -(low + 1);
}

Simple Merge Sort in Java

I'm trying to create a simple merge sort program within Java. I feel like it should work but when I go to run it I get a stack overflow error:
Stack overflow at MergeSort.mergeSort(MergeSort.java:24)
I have seen several other people on here have similar problems with such code but am struggling to fix mine. Any help would be appreciated.
Main code:
import static java.lang.System.*;
import java.util.Arrays;
public class MergeSort {
private static int passCount;
public static void mergeSort(Comparable[] list)
{
passCount = 0;
mergeSort(list, 0, list.length);
}
private static void mergeSort(Comparable[] list, int front, int back) //O( Log N )
{
int mid = (front + back) / 2;
if (mid == front)
return;
mergeSort(list, front, mid);
mergeSort(list, front, back);
merge(list, front, back);
}
private static void merge(Comparable[] list, int front, int back) //O(N)
{
Comparable[] temp = new Comparable[back - front];
int i = front;
int j = (front + back) / 2;
int k = 0;
int mid = j;
while (i < mid && j < back)
{
if (list[i].compareTo(list[j]) < 0)
{
temp[k] = list[i];
k++; i++;
}
else
{
temp[k] = list[j];
k++; i++;
}
while(i < mid)
{
temp[k++] = list[i++];
}
while (j < back)
{
temp[k++] = list[j++];
}
for (i = 0; i < back - front; ++i)
{
list[front + i] = temp[i];
}
out.println("pass " + passCount++ + " " + Arrays.toString(list) + "\n");
}
}
}
My runner:
public class MergeSortRunner
{
public static void main(String args[])
{
MergeSort.mergeSort(new Comparable[]{ 9, 5, 3, 2 });
System.out.println("\n");
MergeSort.mergeSort(new Comparable[]{ 19, 52, 3, 2, 7, 21 });
System.out.println("\n");
MergeSort.mergeSort(new Comparable[]{ 68, 66, 11, 2, 42, 31});
System.out.println("\n");
}
}
You need to change:
mergeSort(list, front, back);
To:
mergeSort(list, mid, back);
It's going to result in an infinite call to mergeSort because you don't change any of the input parameters between calls.
You will also probably want to change:
if(mid==front) return;
to:
if(back - front <= 1) return;
Also, your implementation choice for this algorithm is likely going to result in a non-stable sort, since you are modifying the list in place. A better option would be to have mergeSort return a list of whatever it is you're sorting, and then implement merge to take two lists as arguments, and then produce a single, merged list.
I know that this is really really late, but I have the correct answer you are looking for!
import static java.lang.System.*;
import java.util.Arrays;
public class MergeSort{
private static int passCount;
public static void mergeSort(int[] list)
{
passCount=0;
mergeSort(list, 0, list.length);
}
private static void mergeSort(int[] list, int front, int back) //O( Log N )
{
int mid = (front+back)/2;
if(mid==front) return;
mergeSort(list, front, mid);
mergeSort(list, mid, back);
merge(list, front, back);
}
private static void merge(int[] list, int front, int back) //O(N)
{
int dif = back-front;
int[] temp = new int[dif];
int beg = front, mid = (front+back)/2;
int saveMid = mid;
int spot = 0;
while(beg < saveMid && mid < back) {
if(list[beg] < list[mid]) {
temp[spot++] = list[beg++];
} else {
temp[spot++] = list[mid++];
}
}
while(beg < saveMid)
temp[spot++] = list[beg++];
while(mid < back)
temp[spot++] = list[mid++];
for(int i = 0; i < back-front; i++) {
list[front+i] = temp[i];
}
System.out.println("pass " + passCount++ + " " + Arrays.toString(list) + "\n");
}
}
Here is the runner:
public class MergeSortRunner {
public static void main(String[] args) {
MergeSort.mergeSort(new int[]{9,5,3,2});
System.out.println();
MergeSort.mergeSort(new int[]{19,52,3,2,7,21});
System.out.println();
MergeSort.mergeSort(new int[]{68,66,11,2,42,31});
System.out.println();
}
}
As it turns out, using while loops to loop through the list can help you return the proper values!
Try to change
if(mid==front) return;
To
if(back-front<=1) return;

Recursive method stuck at infinite loop

I am currently working with mergeSort. I have come across a task that ask me specifically to NOT use temporary arrays to create a mergeSort. So recursion is the way to go. Here's my code:
UPDATE: Posted the rest of the code, by request.
public class RecursiveMergeSort {
public static void mergeSort(int[] list){
mergeSort(list, 0, list.length - 1);
}
private static void mergeSort(int[] list, int low, int high){
if(low < high){
//recursive call to mergeSort, one for each half
mergeSort(list, low, (high/2));
mergeSort(list, list.length/2, high);
int[] temp = merge(list, low, high);
System.arraycopy(temp, 0, list, low, high - low + 1);
}
}
private static int[] merge(int[] list, int low, int high){
int[] temp = new int[high - low + 1];
int mid = (high/2) + 1;
if(list[low] < list[mid] && mid < list.length){
temp[low] = list[low];
temp[mid] = list[mid];
}
if(list[low] > list[mid] && mid < list.length){
temp[low] = list[mid];
temp[mid] = list[low];
}
low++;
mid++;
return temp;
}
public static void main(String[] args) {
int[] list = {2, 3, 4, 5};
mergeSort(list);
for(int i = 0; i < list.length; i++){
System.out.println(list[i] + " ");
}
}
}
I'm supposed to recursively divide and conquer this. However, I get stuck at a infinite loop that causes stack overflow(naturally) for the second half. And I am at a complete loss for figuring out a gentle and smooth way to tell my method to keep splitting. Bear in mind that the if statement in my snippet is supposed to be there, by courtesy of our teacher.
The low and high values are the lowest and the highest Index for the array passed in the method.
Need a pointer please.

Implementing a binary insertion sort using binary search in Java

I'm having trouble combining these two algorithms together. I've been asked to modify Binary Search to return the index that an element should be inserted into an array. I've been then asked to implement a Binary Insertion Sort that uses my Binary Search to sort an array of randomly generated ints.
My Binary Search works the way it's supposed to, returning the correct index whenever I test it alone. I wrote out Binary Insertion Sort to get a feel for how it works, and got that to work as well. As soon as I combine the two together, it breaks. I know I'm implementing them incorrectly together, but I'm not sure where my problem lays.
Here's what I've got:
public class Assignment3
{
public static void main(String[] args)
{
int[] binary = { 1, 7, 4, 9, 10, 2, 6, 12, 3, 8, 5 };
ModifiedBinaryInsertionSort(binary);
}
static int ModifiedBinarySearch(int[] theArray, int theElement)
{
int leftIndex = 0;
int rightIndex = theArray.length - 1;
int middleIndex = 0;
while(leftIndex <= rightIndex)
{
middleIndex = (leftIndex + rightIndex) / 2;
if (theElement == theArray[middleIndex])
return middleIndex;
else if (theElement < theArray[middleIndex])
rightIndex = middleIndex - 1;
else
leftIndex = middleIndex + 1;
}
return middleIndex - 1;
}
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int i = 0;
int[] returnArray = new int[theArray.length + 1];
for(i = 0; i < theArray.length; i++)
{
returnArray[ModifiedBinarySearch(theArray, theArray[i])] = theArray[i];
}
for(i = 0; i < theArray.length; i++)
{
System.out.print(returnArray[i] + " ");
}
}
}
The return value I get for this when I run it is 1 0 0 0 0 2 0 0 3 5 12. Any suggestions?
UPDATE: updated ModifiedBinaryInsertionSort
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int index = 0;
int element = 0;
int[] returnArray = new int[theArray.length];
for (int i = 1; i < theArray.lenght - 1; i++)
{
element = theArray[i];
index = ModifiedBinarySearch(theArray, 0, i, element);
returnArray[i] = element;
while (index >= 0 && theArray[index] > element)
{
theArray[index + 1] = theArray[index];
index = index - 1;
}
returnArray[index + 1] = element;
}
}
Here is my method to sort an array of integers using binary search.
It modifies the array that is passed as argument.
public static void binaryInsertionSort(int[] a) {
if (a.length < 2)
return;
for (int i = 1; i < a.length; i++) {
int lowIndex = 0;
int highIndex = i;
int b = a[i];
//while loop for binary search
while(lowIndex < highIndex) {
int middle = lowIndex + (highIndex - lowIndex)/2; //avoid int overflow
if (b >= a[middle]) {
lowIndex = middle+1;
}
else {
highIndex = middle;
}
}
//replace elements of array
System.arraycopy(a, lowIndex, a, lowIndex+1, i-lowIndex);
a[lowIndex] = b;
}
}
How an insertion sort works is, it creates a new empty array B and, for each element in the unsorted array A, it binary searches into the section of B that has been built so far (From left to right), shifts all elements to the right of the location in B it choose one right and inserts the element in. So you are building up an at-all-times sorted array in B until it is the full size of B and contains everything in A.
Two things:
One, the binary search should be able to take an int startOfArray and an int endOfArray, and it will only binary search between those two points. This allows you to make it consider only the part of array B that is actually the sorted array.
Two, before inserting, you must move all elements one to the right before inserting into the gap you've made.
I realize this is old, but the answer to the question is that, perhaps a little unintuitively, "Middleindex - 1" will not be your insertion index in all cases.
If you run through a few cases on paper the problem should become apparent.
I have an extension method that solves this problem. To apply it to your situation, you would iterate through the existing list, inserting into an empty starting list.
public static void BinaryInsert<TItem, TKey>(this IList<TItem> list, TItem item, Func<TItem, TKey> sortfFunc)
where TKey : IComparable
{
if (list == null)
throw new ArgumentNullException("list");
int min = 0;
int max = list.Count - 1;
int index = 0;
TKey insertKey = sortfFunc(item);
while (min <= max)
{
index = (max + min) >> 1;
TItem value = list[index];
TKey compKey = sortfFunc(value);
int result = compKey.CompareTo(insertKey);
if (result == 0)
break;
if (result > 0)
max = index - 1;
else
min = index + 1;
}
if (index <= 0)
index = 0;
else if (index >= list.Count)
index = list.Count;
else
if (sortfFunc(list[index]).CompareTo(insertKey) < 0)
++index;
list.Insert(index, item);
}
Dude, I think you have some serious problem with your code. Unfortunately, you are missing the fruit (logic) of this algorithm. Your divine goal here is to get the index first, insertion is a cake walk, but index needs some sweat. Please don't see this algorithm unless you gave your best and desperate for it. Never give up, you already know the logic, your goal is to find it in you. Please let me know for any mistakes, discrepancies etc. Happy coding!!
public class Insertion {
private int[] a;
int n;
int c;
public Insertion()
{
a = new int[10];
n=0;
}
int find(int key)
{
int lowerbound = 0;
int upperbound = n-1;
while(true)
{
c = (lowerbound + upperbound)/2;
if(n==0)
return 0;
if(lowerbound>=upperbound)
{
if(a[c]<key)
return c++;
else
return c;
}
if(a[c]>key && a[c-1]<key)
return c;
else if (a[c]<key && a[c+1]>key)
return c++;
else
{
if(a[c]>key)
upperbound = c-1;
else
lowerbound = c+1;
}
}
}
void insert(int key)
{
find(key);
for(int k=n;k>c;k--)
{
a[k]=a[k-1];
}
a[c]=key;
n++;
}
void display()
{
for(int i=0;i<10;i++)
{
System.out.println(a[i]);
}
}
public static void main(String[] args)
{
Insertion i=new Insertion();
i.insert(56);
i.insert(1);
i.insert(78);
i.insert(3);
i.insert(4);
i.insert(200);
i.insert(6);
i.insert(7);
i.insert(1000);
i.insert(9);
i.display();
}
}

Categories

Resources