While loop doesnt end in iterative binary search - java

I'm currently writing a binary search that uses iteration instead of recursion and its not returning anything. I've debugged it down to the while loop not ending but I can't seem to figure out where I went wrong.
Here is the code:
public static <E extends Comparable> boolean binarySearchIterative(E[] array, E obj) {
int first = 0;
int last = array.length - 1;
while(first <= last) {
int middle = (first + last) / 2;
if(array[middle].equals(obj)) return true;
else if(obj.compareTo(array[middle]) < 0) first = middle - 1;
else first = middle + 1;
}
return false;
}
And yes, my list is ordered ;)

In the second else if part you need to set last instead of first -
else if(obj.compareTo(array[middle]) < 0) last = middle - 1;

Related

Incrementing statements to track comparisons in recursive method

I am trying to construct a recursive binary search method that searches a sorted array of comparable objects for an object of interest. This is part of a larger algorithm that searches a collection of sorted arrays and looks for elements common to all arrays in the collection. The goal is to make the search/comparison portion of the algorithm as efficient as possible. A linear solution should be possible. This is the method:
private static boolean BinarySearch(Comparable[] ToSearch, Comparable ToFind, int first, int last){
boolean found = false;
int mid = first + (last - first) / 2;
comparisons++;
if(first > last){
found = false;
}
else if(ToFind.compareTo(ToSearch[mid]) == 0){
found = true;
comparisons++;
}
else if(ToFind.compareTo(ToSearch[mid]) < 0) {
found = BinarySearch(ToSearch, ToFind, first, mid - 1);
comparisons++;
}
else{
found = BinarySearch(ToSearch, ToFind,mid + 1, last);
comparisons++;
}
return found;
}
The problem I am having is tracking the number of comparisons through the recursion. Because I have to count the comparisons that evaluate to false as well as true, I tried to placing the comparison incrementing statement inside each selection statement but this does not work because the statement is not incremented if the statement evaluates to false. I also cannot place them between the selection statements because that would give me else without if erros. I am wondering if it was a bad idea to use recursion at all for the search but I want to believe it is possible. Any help would be appreciated.
Perhaps you could set a variable in each if block with the number of comparisons it took to get there, and add it at the end?
private static boolean BinarySearch(Comparable[] ToSearch, Comparable ToFind, int first, int last){
boolean found = false;
int newComparisons = 0;
int mid = first + (last - first) / 2;
if(first > last){
found = false;
newComparisons = 1;
}
else if(ToFind.compareTo(ToSearch[mid]) == 0){
found = true;
newComparisons = 2;
}
else if(ToFind.compareTo(ToSearch[mid]) < 0) {
found = BinarySearch(ToSearch, ToFind, first, mid - 1);
newComparisons = 3;
}
else{
found = BinarySearch(ToSearch, ToFind,mid + 1, last);
newComparisons = 3;
}
comparisons += newComparisons;
return found;
}

What counts as a binary search comparison?

I'm writing a program that determines how many comparisons it takes to run a binary search algorithm for a given number and sorted array. What I don't understand is what counts as a comparison.
// returns the number of comparisons it takes to find key in sorted list, array
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (true) {
if (left > right) {
mid = -1;
break;
}
else {
mid = (left + right)/2;
if (key < array[mid]) {
i++;
right = mid - 1;
}
else if (key > array[mid]) {
i++;
left = mid + 1;
}
else {
break; // success
}
}
}
return i;
}
The function returns i, which is supposed to be the total number of comparisons made in finding the key in array. But what defines a comparison? Is it any time there is a conditional?
Thanks for any help, just trying to understand this concept.
Usually, a comparison occurs each time the key is compared to an array element. The code seems to not be counting that, though. It is counting how many times one of the search boundaries (left or right) is changed. It's not exactly the same thing being counted, but it's pretty close to the same thing, since the number of times a boundary is shifted is directly related to the number of times through the loop and hence to the number of times a comparison is made. At most, the two ways of counting will be off by 1 or 2 (I didn't bother to figure that out exactly).
Note also that if one were to use the usual definition, the code could be rewritten to use Integer.compare(int,int) do a single comparison of key with array[mid] to determine whether key was less than, equal to, or greater than array[mid].
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right)/2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
}
else if (comp > 0) {
left = mid + 1;
}
else {
break; // success
}
}
return i;
}

Manual binary search by passing just an object

Currently stuck on a problem with binary search that is asking me to pass one parameter with is an object.
But is it possible to do this?? Normally I would use two parameters for a problem like this.
Normally with binary search I use-->
int binarySearch(int[] list, int searchItem)
{
int mid=0;
int start=0;
int end=list.length-1;
boolean found=false;
//Loop until found or end of list.
while (start <= end && !found)
{
mid = (start + end) / 2;
if (list[mid] == searchItem)
found = true;
else
if (list[mid] > searchItem)
end = mid - 1;
else
start = mid + 1;
}
if(found)
return mid;
else
return(-1);
}
But is it possible to just pass in one parameter like this?? I need to search an array list.
public int binarySearch(Moon searchItem){
int mid = 0;
int start = 0;
int end = moons.size() -1;
boolean found = false;
while(start <= end && !found){
mid = (start + end) / 2;
if(moons.get(mid).equals(searchItem)){
found = true;
}
else{
if(???)) {
}
else
etc etc
}
}
return 0;
}
First you should go through this question: How to compare objects by multiple fields
Then, implement Comparable to Moon class. If you can't change Moon class, then you've to create Comparator.
You'll need to override compareTo method in Moon class which can be used in place of ??? in your question.

How do I add logic to a sorted array delete algorithm to account for a "node not found" scenario?

I was assigned to write a delete algorithm for my sorted array structure. It continues to be a source of problems for my program because, in certain instances, it is completing the delete when it should be returning False for "node not found". So the delete function works, but it does it even when the node is not found. Where is the flaw in my logic?
public boolean delete(String targetListing)
{
int low = 0;
int high = next - 1;
int i = (low + high) / 2;
//check to see if target listing is the same as the current node key field
while(data[i].getName().compareToIgnoreCase(targetListing) != 0 && high != low)
{
if(data[i].getName().compareToIgnoreCase(targetListing) >= 1)
{
high = i - 1; //eliminate the bottom of the array
}
else
{
low = i + 1; //eliminate the top of the array
}
i = (low + high) / 2;
}
//this is my logic to determine if the node was found or not
//I also tried if(low == high) but sometimes that would be true at the
//at the position that the node was found
if(i == next || i < 0)
{
return false; //node not found
}
for(int j = i; j < next - 1; j++)
{
data[j] = data[j + 1];
}
next = next - 1;
data[next] = null;
return true;//node found and deleted
If anyone could also point me to a good example of a sorted array delete algorithm that accounts for a node not found scenario I would really appreciate it. I would have thought that would be a very easy thing to find, but I am having a hard time finding it.
Simplest answer: Replace your if(i == next || i < 0) with if(data[i].getName().compareToIgnoreCase(targetListing) != 0) -- in other words, check that you've actually found a match rather than simply having narrowed down to a single possibility.

Binary Search w/o Library Methods

I am trying to construct a binarySearch method that goes through a sorted array, and evaluates whether a given element, given as int target, is present. It will do so by evaluating whether the mean value is greater or less than the target value, and will loop through the first or second half of the array accordingly.
I think I have the basic code down, but I am running into some problems:
int target = 0; (returns true) => correct
int target = (3, 6, 9); (returns false) => should return true
int target = (15, 19, 21, 90); returns "java.lang.ArrayIndexOutOfBoundsException: 15" => should be true
I imagine it has to do with my for statements in the respective if cases, but I have tried to debug and cannot. Also, I not permitted to use library methods.
Hopefully this question is helpful for other beginners like me. I would think it explores some java concepts like syntax, logic, and basic use Thanks for the help.
public class ArrayUtilities
{
public static void main(String[] args)
{
int[] arrayBeingSearched = {0, 3, 6, 9, 12, 15, 19, 21, 90};
int target = 90;
System.out.println("linear: " + linearSearch(arrayBeingSearched, target));
System.out.println("binary: " + binarySearch(arrayBeingSearched, target));
}
public static boolean binarySearch(int[] arrayBeingSearched, int target)
{
boolean binarySearch = false;
for (int i = 0; i < arrayBeingSearched.length; i++){
int left = 0; //array lower bound
int right = arrayBeingSearched.length - 1; //array upper bound
int middle = ((right - left) / (2)); //array mean
if(arrayBeingSearched[middle] == target){
binarySearch = true;
}
else if(arrayBeingSearched[middle] < target){
for(int j = middle + 1; j < arrayBeingSearched.length - 1; j ++){
int newLeft = arrayBeingSearched[j ++];
if(arrayBeingSearched[newLeft] == target){
binarySearch = true;
break;
}
else{
binarySearch = false;
}
}
}
else if(arrayBeingSearched[middle] > target)
for(int l = 0; l < middle - 1; l ++){
int newRight = arrayBeingSearched[l ++];
if(arrayBeingSearched[newRight] == target){
binarySearch = true;
break;
}
else{
binarySearch = false;
}
}
else{
binarySearch = false;
}
}
return binarySearch;
}
}
Okay, based on the comments, would this be a better representation? The first comment answered my question mostly but I just wanted to follow up:
public static boolean binarySearch(int[] array, int target)
{
int start = 0;
int end = array.length - 1;
while (start <= end)
{
int middle = start + (end - start)/2;
if (array[middle] == target) {
return true;
}
else if (array[middle] > target)
{
end = middle - 1;
}
else start = middle + 1;
}
return false;
}
}
This is a bad start:
for (int i = 0; i < arrayBeingSearched.length; i++)
That's a linear search, with something else within it. I haven't followed exactly what you're doing, but I think you should probably start again... with a description of binary search in front of you.
Typically a binary search loop looks something like:
int left = 0; // Inclusive lower bound
int right = arrayBeingSearch.length; // Exclusive upper bound
while (left < right) {
// Either change left, change right, or return success
// based on what you find
}
When your middle element is smaller than the target, you do this
int newLeft = arrayBeingSearched[j ++];
if(arrayBeingSearched[newLeft] == target) //...
And the equivalent when it's larger.
That is, you are taking an element of the array and using it as an index. Your array could contain only one element with a value of 1000, which is why you're running into an ArrayIndexOutOfBoundsException.
I'm sure there are other problems (see Jon's answer), but I wanted to mention that code like this:
for(int j = middle + 1; j < arrayBeingSearched.length - 1; j ++){
int newLeft = arrayBeingSearched[j ++];
will not do what you want. The for statement says that each time the program goes through the loop, it will add 1 to j (at the end of the loop code). But the next statement will use j as an index and then add 1 to it. The result is that each time you go through the loop, 1 will be added to j twice, so you're basically looking only at every other element. If this were otherwise correct (which I don't think it is), I'd say you definitely need to remove the ++ from the second line.

Categories

Resources