Manual binary search by passing just an object - java

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.

Related

How to use binary search of a sorted list and then count the comparisons

I am trying to use my sorted list and implement it with binary search. Then i want to count the number of comparisons it takes to find the key. my code is:
public class BinarySearch {
private static int comparisions = 0;
public static void main(String[] args) {
int [] list = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int i = BinarySearch.BinSearch(list, 20);
System.out.println(comparisions);
}
public static int BinSearch(int[] list, int key) {
int low = 0;
int high = list.length - 1;
int mid = (high + low) / 2;
if (key < list[mid]) {
high = mid - 1;
comparisions++;
} else if (key == list[mid]) {
return mid;
comparisions++;
} else {
low = mid + 1;
comparisions++;
}
return -1;
}
}
So far it only gives me 1 for the comparison no matter what number is the key.
Your code is missing the looping part of the search, that looping can either be done using recursion or using a while loop. In both cases you have to ask yourself wether or not you just want to know the count or actually return the count of comparisons. Since your method right now returns the index, it cannot easily return the count of comparisons at the same time. For that to work you either need to return an array of two ints or a custom class IndexAndComparisonCount { ... }.
If you use a recursive approach you need to increment whenever you do a comparison and when you do a recursive call you need to get the return value of that recursive call and increment the comparisonCount the call returned by 1:
if (... < ...) {
IndexAndComparisonCount ret = BinSearch(...);
ret.comparisonCount += 1;
return ret;
} else if (... > ...) {
IndexAndComparisonCount ret = BinSearch(...);
ret.comparisonCount += 2; // since you did compare twice already
return ret;
} else {
return new IndexAndComparisonCount(mid, 2); // you compared twice as well
}

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;
}

While loop doesnt end in iterative binary search

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;

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