Can I get some help please? I have tried many methods to get this to work i got the array sorted and to print but after that my binary search function doesnt want to run and give me right results. It always gives me -1. Any help?
public class BinarySearch {
public static final int NOT_FOUND = -1;
public static int binarySearch(double[] a, double key) {
int low = 0;
int high = a.length -1;
int mid;
while (low<=high) {
mid = (low+high) /2;
if (mid > key)
high = mid -1;
else if (mid < key)
low = mid +1;
else
return mid;
}
return NOT_FOUND;
}
public static void main(String[] args) {
double key = 10.5, index;
double a[] ={10,5,4,10.5,30.5};
int i;
int l = a.length;
int j;
System.out.println("The array currently looks like");
for (i=0; i<a.length; i++)
System.out.println(a[i]);
System.out.println("The array after sorting looks like");
for (j=1; j < l; j++) {
for (i=0; i < l-j; i++) {
if (a[i] > a[i+1]) {
double temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
}
for (i=0;i < l;i++) {
System.out.println(a[i]);
}
System.out.println("Found " + key + " at " + binarySearch(double a[], key));
}
}
you are not actually comparing with the array values. in
while (low <= high) {
mid = (low + high) / 2;
if (mid > key) {
high = mid - 1;
} else if (mid < key) {
low = mid + 1;
} else {
return mid;
}
}
Instead use this section
while (low <= high) {
mid = (low + high) / 2;
if (a[mid] > key) {
high = mid - 1;
} else if (a[mid] < key) {
low = mid + 1;
} else {
return mid;
}
}
You were correct to find the indexes, but what you were doing is that you were just comparing index number with your key, which is obviously incorrect. When you write a[mid] you will actually compare your key with the number which is at index mid.
Also the last line of code is giving compile error, it should be
System.out.println("Found " + key + " at " + binarySearch(a, key));
Here
if (mid > key)
high = mid -1;
else if (mid < key)
low = mid +1;
else
return mid;
You're comparing index to a value (key) in array. You should instead compare it to a[mid]
And,
System.out.println("Found " + key + " at " + binarySearch(double a[], key));
Should be
System.out.println("Found " + key + " at " + binarySearch(a, key));
public static double binarySearch(double[] a, double key) {
if (a.length == 0) {
return -1;
}
int low = 0;
int high = a.length-1;
while(low <= high) {
int middle = (low+high) /2;
if (b> a[middle]){
low = middle +1;
} else if (b< a[middle]){
high = middle -1;
} else { // The element has been found
return a[middle];
}
}
return -1;
}
int binarySearch(int list[], int lowIndex, int highIndex, int find)
{
if (highIndex>=lowIndex)
{
int mid = lowIndex + (highIndex - lowIndex)/2;
// If the element is present at the
// middle itself
if (list[mid] == find)
return mid;
// If element is smaller than mid, then
// it can only be present in left subarray
if (list[mid] > find)
return binarySearch(list, lowIndex, mid-1, find);
// Else the element can only be present
// in right subarray
return binarySearch(list, mid+1, highIndex, find);
}
// We reach here when element is not present
// in array
return -1;
}
I somehow find the iterative version not quite easy to read, recursion makes it nice and easy :-)
public class BinarySearch {
private static int binarySearchMain(int key, int[] arr, int start, int end) {
int middle = (end-start+1)/2 + start; //get index of the middle element of a particular array portion
if (arr[middle] == key) {
return middle;
}
if (key < arr[middle] && middle > 0) {
return binarySearchMain(key, arr, start, middle-1); //recurse lower half
}
if (key > arr[middle] && middle < arr.length-1) {
return binarySearchMain(key, arr, middle+1, end); //recurse higher half
}
return Integer.MAX_VALUE;
}
public static int binarySearch(int key, int[] arr) { //entry point here
return binarySearchMain(key, arr, 0, arr.length-1);
}
}
Here is a solution without heap. The same thing can be done in an array.
If we need to find 'k' largest numbers, we take an array of size 'k' populated with first k items from the main data source. Now, keep on reading an item, and place it in the result array, if it has a place.
public static void largestkNumbers() {
int k = 4; // find 4 largest numbers
int[] arr = {4,90,7,10,-5,34,98,1,2};
int[] result = new int[k];
//initial formation of elems
for (int i = 0; i < k; ++i) {
result[i] = arr[i];
}
Arrays.sort(result);
for ( int i = k; i < arr.length; ++i ) {
int index = binarySearch(result, arr[i]);
if (index > 0) {
// insert arr[i] at result[index] and remove result[0]
insertInBetweenArray(result, index, arr[i]);
}
}
}
public static void insertInBetweenArray(int[] arr, int index, int num) {
// insert num at arr[index] and remove arr[0]
for ( int i = 0 ; i < index; ++i ) {
arr[i] = arr[i+1];
}
arr[index-1] = num;
}
public static int binarySearch(int[] arr, int num) {
int lo = 0;
int hi = arr.length - 1;
int mid = -1;
while( lo <= hi ) {
mid = (lo+hi)/2;
if ( arr[mid] > num ) {
hi = mid-1;
} else if ( arr[mid] < num ) {
lo = mid+1;
} else {
return mid;
}
}
return mid;
}
int BinSearch(int[] array, int size, int value)
{
if(size == 0) return -1;
if(array[size-1] == value) return size-1;
if(array[0] == value) return 0;
if(size % 2 == 0) {
if(array[size-1] == value) return size-1;
BinSearch(array,size-1,value);
}
else
{
if(array[size/2] == value) return (size/2);
else if(array[size/2] > value) return BinSearch(array, (size/2)+1, value);
else if(array[size/2] < value) return (size/2)+BinSearch(array+size/2, size/2, value);
}
}
or
Binary Search in Array
/**
* Find whether 67 is a prime no
* Domain consists 25 of prime numbers
* Binary Search
*/
int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
int min = 0,
mid,
max = primes.length,
key = 67,
count= 0;
boolean isFound = false;
while (!isFound) {
if (count < 6) {
mid = (min + max) / 2;
if (primes[mid] == key) {
isFound = true;
System.out.println("Found prime at: " + mid);
} else if (primes[mid] < key) {
min = mid + 1;
isFound = false;
} else if (primes[mid] > key) {
max = mid - 1;
isFound = false;
}
count++;
} else {
System.out.println("No such number");
isFound = true;
}
}
/**
HOPE YOU LIKE IT
A.K.A Binary Search
Take number array of 10 elements, input a number a check whether the number
is present:
**/
package array;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
class BinaryS
{
public static void main(String args[]) throws IOException
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter a number: ");
int n=Integer.parseInt(br.readLine());
int a[]={10,20,30,40,50,60,70,80,90,100};
int upper=a.length-1,lower=0,mid;
boolean found=false;
int pos=0;
while(lower<=upper)
{
mid=(upper+lower)/2;
if(n<a[mid])upper=mid-1;
else if(n>a[mid])lower=mid+1;
else
{
found=true;
pos=mid;
break;
}
}
if(found)System.out.println(n+" found at index "+pos);
else System.out.println(n+" not found in array");
}
}
Well I know I am posting this answer much later.
But according to me its always better to check boundary condition at first.
That will make your algorithm more efficient.
public static int binarySearch(int[] array, int element){
if(array == null || array.length == 0){ // validate array
return -1;
}else if(element<array[0] || element > array[array.length-1]){ // validate value our of range that to be search
return -1;
}else if(element == array[0]){ // if element present at very first element of array
return 0;
}else if(element == array[array.length-1]){ // if element present at very last element of array
return array.length-1;
}
int start = 0;
int end = array.length-1;
while (start<=end){
int midIndex = start + ((end-start)/2); // calculate midIndex
if(element < array[midIndex]){ // focus on left side of midIndex
end = midIndex-1;
}else if(element > array[midIndex]){// focus on right side of midIndex
start = midIndex+1;
}else {
return midIndex; // You are in luck :)
}
}
return -1; // better luck next time :(
}
static int binarySearchAlgorithm() {
// Array should be in sorted order. Mandatory requirement
int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int lowIndex = 0;
int valueToFind = 8;
int highIndex = a.length - 1;
while (lowIndex <= highIndex) {
//Finding the midIndex;
int midIndex = (highIndex + lowIndex) / 2;
// Checking if midIndex value of array contains the value to be find.
if (a[midIndex] == valueToFind) {
return midIndex;
}
// Checking the mid Index value is less than the value to be find.
else if (a[midIndex] < valueToFind) {
// If Yes, changing the lowIndex value to midIndex value + 1;
lowIndex = midIndex + 1;
} else if (a[midIndex] > valueToFind) {
// If Yes, changing the highIndex value to midIndex value - 1;
highIndex = midIndex - 1;
} else {
return -1;
}
}
return -1;
}
Related
I going to do searching the value in the array, did I need to create a method to handle it? For example, the array logged 32,21,13,44,22, and I going to find 22 of the comparison. How can I implement this?
public class binarySearch {
public static void main(String [] args) {
int i = binarySearch(0, new int[]{32,21,13,44,22});
System.out.println("Iterations: " + i);
}
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;
}
}
My final answer is here. May help you all in the future.
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;
}
If you have shuffled array, all you can do is go through an array and find your number.
BinarySearch works only with sorted array. I think your solution could look like this:
public static int binarySearch(int[] arr, int key) {
Arrays.sort(arr);
return Arrays.binarySearch(arr, key);
}
I am trying to implement merge sort algorithm with some optimization like using temp storage only once and avoiding the copy till the last.Everything is okay and many test files are passing except some.The thing that is happening here is with unsorted array,the algorithm is showing some problems.I have written print statements in my code trying to reach the problem,but unable to do so.As many tests are passing,i believe there is nothing major wrong in the program,just it misses something.
I have tried to implement the program and it is successful in many ways,just 3 cases doesn't pass.But,the main problem i am facing is that test case Mergesort_two() doesn't pass because its simple .It's just calling two numbers and asserting in sorted form,but my program is denying it.I believe its a minor error which i am unable to figure out.
public static void mergesort(int[] input, int[] temp,
int start, int end,
boolean intoTemp) {
if (start == end) {
return;
}
if ((start + 1) == end) {
if (intoTemp == true) {
temp[start] = input[start];
return;
}
}
if (start < end) {
if (intoTemp == false) {
intoTemp = true;
int mid = (start + end)/2;
mergesort(input, temp, start, mid, intoTemp);
mergesort(input, temp, mid, end, intoTemp);
merge(input, temp, start, mid, end);
System.out.println("Input Array: " + Arrays.toString(input) +
" Temp: " + Arrays.toString(temp) + " intoTemp: " +
intoTemp + "Start Mid End: " + start + " " + mid + " " + end);
}
else if(intoTemp == true) {
intoTemp = false;
int mid = (start + end)/2;
mergesort(input, temp, start, mid, intoTemp);
mergesort(input, temp, mid, end, intoTemp);
merge(temp, input, start, mid, end);
System.out.println("Input Array: " + Arrays.toString(input) +
" Temp: " + Arrays.toString(temp) + " intoTemp: " +
intoTemp + "Start Mid End: " + start + " " + mid + " " + end);
}
}
if (start == 0 && end == input.length) {
System.arraycopy(temp, 0, input, 0, input.length);
}
}
/** Merges input[start...mid-1] with input[mid...end-1] into
* output[start...end-1]. The input array should not be modified at
* all, and only start...end-1 of the output array should be changed.
*
* #param input Input array
* #param output Output array
* #param start Starting index
* #param mid Midpoint index
* #param end Ending index+1
*/
public static void merge(int[] input, int[] output,
int start, int mid, int end) {
if (input == null || (start == mid && mid == end)) {
return;
}
int i = start;
int j = mid - 1;
int k = mid;
int index = start;
while (i <= j && k < end) {
if (input[i] <= input[k]) {
output[index] = input[i];
i++;
index++;
}
if (input[i] > input[k]) {
output[index] = input[i];
k++;
index++;
}
}
while (i <= j) {
output[index] = input[i];
index++;
i++;
}
while (k < end) {
output[index] = input[k];
index++;
k++;
}
}
}
////// Test Cases
#Test
public void testMergesort_Two() {
System.out.println("mergesort one element");
int[] array = new int[2];
// Already sorted
array[0] = 10; array[1] = 13;
CSSE240_Assign4.mergesort(array);
assertEquals(array[0], 10);
assertEquals(array[1], 13);
// Unsorted
array[0] = 3; array[1] = -4;
CSSE240_Assign4.mergesort(array);
assertEquals(array[0], -4);
assertEquals(array[1], 3);
}
#Test
public void testMergesort_Large() {
System.out.println("mergesort one large");
Random rng = new Random();
for(int s = 3; s < 20; ++s) {
int[] array = new int[s];
int[] orig = new int[s];
// Fill with random values.
for(int i = 0; i < s; ++i) {
array[i] = rng.nextInt();
orig[i] = array[i];
}
CSSE240_Assign4.mergesort(array);
Arrays.sort(orig);
// Make sure both arrays agree
for(int i = 0; i < s; ++i)
assertEquals(orig[i], array[i]);
}
}
#Test
public void testMergeInterleaved() {
// Various cases where the left/right halves are interleaved. We test
// this by picking a modulo m and moving all the elements where
// e % m < m/2 to the right side.
System.out.println("merge reverse sorted");
for(int s = 3; s < 20; ++s) {
int[] array = new int[s];
int mid = 0;
// Move the elements of the array around into the two halves.
for(int m = 2; m < 5; ++m) {
// Populate the array with 0...s-1
for (int i = 0; i < s; ++i) {
array[i] = i;
}
int[] left = new int[s];
int[] right = new int[s];
int lc = 0, rc = 0;
for(int i = 0; i < s; ++i)
if(array[i] % m < m/2)
right[rc++] = array[i];
else
left[lc++] = array[i];
// Copy back into the array
int j = 0;
for(int i = 0; i < lc; ++i)
array[j++] = left[i];
for(int i = 0; i < rc; ++i)
array[j++] = right[i];
mid = lc; // Midpoint
int[] output = new int[s];
Arrays.fill(output, -1);
// TODO: check different endpoints...
CSSE240_Assign4.merge(array, output, 0, mid, s);
for(int i = 0; i < s; ++i)
assertEquals(output[i], i);
}
}
}
testMergesort_Two Failed : expected <-4> but was <3>
testMergeInterleaved Failed: expected <0> but was <1>
testMergeSort_Large Failed : expected:<-1131373963> but was:<-2038582366>
Changes noted in comments.
public static void mergesort(int[] input, int[] temp,
int start, int end,
boolean intoTemp) {
if (start == end) {
return;
}
if ((start + 1) == end) {
if (intoTemp == true) {
temp[start] = input[start];
return;
}
}
if (intoTemp == false) {
intoTemp = true;
int mid = (start + end)/2;
mergesort(input, temp, start, mid, intoTemp);
mergesort(input, temp, mid, end, intoTemp);
merge(temp, input, start, mid, end);
} else {
intoTemp = false;
int mid = (start + end)/2;
mergesort(input, temp, start, mid, intoTemp);
mergesort(input, temp, mid, end, intoTemp);
merge(input, temp, start, mid, end);
}
}
public static void merge(int[] input, int[] output,
int start, int mid, int end) {
int i = start;
int j = mid; // using j instead of k
// and mid instead of j
int index = start;
while (i < mid && j < end) { // using mid
if (input[i] <= input[j]) {
output[index] = input[i];
i++;
index++;
} else { // change
output[index] = input[j]; // was input[i]
j++;
index++;
}
}
while (i < mid) { // using mid
output[index] = input[i];
i++; // changed order for consistency
index++;
}
while (j < end) {
output[index] = input[j];
j++; // changed order for consistency
index++;
}
}
This code, generates a random number, sorts it in ascending order and does the binary search to find a target value. MY QUESTION IS HOW DO I MODIFY THIS CODE TO FIND THE LARGEST INDEX OF THE GIVEN TARGET. For example the array has { 1, 2 , 3, 5, 5, 5, 5}, the target is 5, so the output should be 6 instead of 3. Thankyou.
import java.util.*;
public class Sort
{
public static void main(String args[])
{
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you want? ");
int howMany = in.nextInt();
int [] myArray = getSortedRandomArray(howMany);
System.out.print("\nFor what value would you like to search? ");
int target = in.nextInt();
int index = bsearch ( myArray, target);
if (index >= 0)
{
System.out.println("The value " + target + " occurs at index " + index);
}
else
{
System.out.println("The value " + target + " does not occur in the array. ");
}
}
public static int bsearch(int[] arr, int key)
{
int lo = 0, hi = arr.length - 1;
{
while (lo < hi)
{
int mid = (lo + hi) / 2;
if (arr[mid] <= key)
lo = mid + 1;
if (arr[mid] > key)
hi = mid;
}
if (arr[lo] == key) {
return lo;
}
else if ((arr[lo] != key) && (arr[lo-1] == key)){
return lo - 1;
}
else{
System.out.print("The value " + key + " does not occur in the array. ");
}
return -1 ;
}
public static int[] getSortedRandomArray (int howMany)
{
int[] returnMe = new int [howMany];
Random rand = new Random();
for (int i = 0; i < howMany ; i++)
returnMe[i] = rand.nextInt(Integer.MAX_VALUE) + 1;
for (int i = 1; i <= (howMany - 1); i++)
{
for (int j = 0; j <= howMany - i -1; j++)
{
int tmp = 0;
if (returnMe[j] > returnMe[j+1])
{
tmp = returnMe[j];
returnMe[j] = returnMe[j + 1];
returnMe[j + 1] = tmp;
}
}
}
System.out.print("Here is a random sorted array: ");
for ( int i = 0; i < howMany; i++)
System.out.print(returnMe[i] + " ");
return returnMe;
}
You can do this by modifying the binary search algorithms code like this:
public static int bsearch(int[] arr, int key) {
int lo = 0, hi = arr.length - 1;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (arr[mid] <= key)
lo = mid + 1;
if (arr[mid] > key)
hi = mid;
}
if (arr[lo] == key) {
return lo;
}
else {
return lo - 1;
}
}
This code instead searches for the first number larger than key. That can be any number, 6 or 10000, it doesn't matter. As you can see, if arr[mid] is equal to key, the code will still run on the interval [mid, hi]. Why those two returns at the end? Well if input array is like the one you gave, lo will end being the index of the last 5, but if we add another number at the end of input array, lo will be index of the number behind the last 5. Therefore, we have 2 different cases.
Also, you can't do it with a linear loop like other answers, because that reduces the algorithm to O(n) and it ends just being a linear search on a reduced array.
If you update your bsearch algorithm a little you can ask it to seek higher matches recursively. However whether this is more efficient than a linear loop would depend on what the input array looked like.
public static int bsearch(int[] arr, int key, int lo, int hi) {
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (arr[mid] == key) {
System.out.println("The value " + key + " is found at " + mid);
int higherResult = bsearch(arr, key, mid + 1, hi);
if (higherResult < 0) {
return mid;
}
return higherResult;
}
if (arr[mid] < key) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
return -1;
}
I am attempting to expand a function to find the number of integer matches through Binary Search by resetting the high variable, but it gets stuck in a loop. I am guessing a workaround would be to duplicate this function to obtain the last index to determine the number of matches, but I do not think this would be such an elegant solution.
From this:
public static Matches findMatches(int[] values, int query) {
int firstMatchIndex = -1;
int lastMatchIndex = -1;
int numberOfMatches = 0;
int low = 0;
int mid = 0;
int high = values[values.length - 1];
boolean searchFirst = false;
while (low <= high){
mid = (low + high)/2;
if (values[mid] == query && firstMatchIndex == -1){
firstMatchIndex = mid;
if (searchFirst){
high = mid - 1;
searchFirst = false;
} else {
low = mid + 1;
}
} else if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
}
if (firstMatchIndex != -1) { // First match index is set
return new Matches(firstMatchIndex, numberOfMatches);
}
else { // First match index is not set
return new Matches(-1, 0);
}
}
To something like this:
public static Matches findMatches(int[] values, int query) {
int firstMatchIndex = -1;
int lastMatchIndex = -1;
int numberOfMatches = 0;
int low = 0;
int mid = 0;
int high = values[values.length - 1];
boolean searchFirst = false;
while (low <= high){
mid = (low + high)/2;
if (values[mid] == query && firstMatchIndex == -1){
firstMatchIndex = mid;
if (searchFirst){
high = values[values.length - 1]; // This is stuck in a loop
searchFirst = false;
}
} else if (values[mid] == query && lastMatchIndex == -1){
lastMatchIndex = mid;
if (!searchFirst){
high = mid - 1;
} else {
low = mid + 1;
}
} else if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
}
if (firstMatchIndex != -1) { // First match index is set
return new Matches(firstMatchIndex, numberOfMatches);
}
else { // First match index is not set
return new Matches(-1, 0);
}
}
There is a problem with your code:
high = values[values.length - 1];
should be
high = values.length - 1;
Also you do not need variables like numberOfMatches and searchFirst, we can have rather simple solution.
Now coming to the problem,I understand what you want I think Binary Search is appropriate for such query.
The Best way to do the required is once a match is found you just go forward and backward from that index until a mismatch occurs and this would be both elegant and efficient in calculating the firstMatchIndex and numberOfMatches.
So your function should be:
public static Matches findMatches(int[] values, int query)
{
int firstMatchIndex = -1,lastMatchIndex=-1;
int low = 0,mid = 0,high = values.length - 1;
while (low <= high)
{
mid = (low + high)/2;
if(values[mid]==query)
{
lastMatchIndex=mid;
firstMatchIndex=mid;
while(lastMatchIndex+1<values.length&&values[lastMatchIndex+1]==query)
lastMatchIndex++;
while(firstMatchIndex-1>=0&&values[firstMatchIndex-1]==query)
firstMatchIndex--;
return new Matches(firstMatchIndex,lastMatchIndex-firstMatchIndex+1);
}
else if(values[mid]>query)
high=mid-1;
else low=mid+1;
}
return new Matches(-1,0);
}
Couldn't you just use something like a set to find duplicates?
Something like this:
package example;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class DuplicatesExample {
public static void main(String[] args) {
String[] strings = { "one", "two", "two", "three", "four", "five", "six", "six" };
List<String> dups = getDups(strings);
System.out.println("DUPLICATES:");
for(String str : dups) {
System.out.println("\t" + str);
}
}
private static List<String> getDups(String[] strings) {
ArrayList<String> rtn = new ArrayList<String>();
HashSet<String> set = new HashSet<>();
for (String str : strings) {
boolean added = set.add(str);
if (added == false ) {
rtn.add(str);
}
}
return rtn;
}
}
Output:
DUPLICATES:
two
six
I have split your problems into two parts - using binary search to find a number and counting the number of matches. The first part is resolved by the search function while the second part is resolved by the findMatches function:
public static Matches findMatches(int[] values, int query) {
int leftIndex = -1;
int rightIndex = -1;
int high = values.length - 1;
int matchedIndex = search(values, 0, high, query);
//if at least one match
if (matchedIndex != -1) {
//decrement upper bound of left array
int leftHigh = matchedIndex - 1;
//increment lower bound of right array
int rightLow = matchedIndex + 1;
//loop until no more duplicates in left array
while (true) {
int leftMatchedIndex = search(values, 0, leftHigh, query);
//if duplicate found
if (leftMatchedIndex != -1) {
leftIndex = leftMatchedIndex;
//decrement upper bound of left array
leftHigh = leftMatchedIndex - 1;
} else {
break;
}
}
//loop until no more duplicates in right array
while(true){
int rightMatchedIndex = search(values, rightLow, high, query);
//if duplicate found
if(rightMatchedIndex != -1){
rightIndex = rightMatchedIndex;
//increment lower bound of right array
rightLow = rightMatchedIndex + 1;
} else{
break;
}
}
return new Matches(matchedIndex, rightIndex - leftIndex + 1);
}
return new Matches(-1, 0);
}
private static int search(int[] values, int low, int high, int query) {
while (low <= high) {
int mid = (low + high) / 2;
if (values[mid] == query) {
return mid;
} else if (query < values[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
I found a solution after correcting a mistake with resetting high variable that caused an infinite loop.
public static Matches findMatches(int[] values, int query) {
int firstMatchIndex = -1;
int lastMatchIndex = -1;
int numberOfMatches = 0;
int low = 0;
int mid = 0;
int high = values.length - 1;
while (low <= high){
mid = (low + high)/2;
if (values[mid] == query && firstMatchIndex == -1){
firstMatchIndex = mid;
numberOfMatches++;
high = values.length - 1;
low = mid;
} else if (values[mid] == query && (lastMatchIndex == -1 || lastMatchIndex != -1)){
lastMatchIndex = mid;
numberOfMatches++;
if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
} else if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
}
if (firstMatchIndex != -1) { // First match index is set
return new Matches(firstMatchIndex, numberOfMatches);
}
else { // First match index is not set
return new Matches(-1, 0);
}
}
Not having any knowledge of the data other than sorted a priori is tough.
See this:
Binary Search O(log n) algorithm to find duplicate in sequential list?
This will find the first index of duplicates of k in a sorted array.
Of course this is related to knowing the value of duplicate first but very useful when it is known.
public static int searchFirstIndexOfK(int[] A, int k) {
int left = 0, right = A.length - 1, result = -1;
// [left : right] is the candidate set.
while (left <= right) {
int mid = left + ((right - left) >>> 1); // left + right >>> 1;
if (A[mid] > k) {
right = mid - 1;
} else if (A[mid] == k) {
result = mid;
right = mid - 1; // Nothing to the right of mid can be
// solution.
} else { // A[mid] < k
left = mid + 1;
}
}
return result;
}
This will find a dupe in log(n) time but is fragile in that the data must be sorted as well as increasing by 1 and in the range 1..n.
static int findeDupe(int[] array) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
if (array[mid] == mid) {
low = mid + 1;
} else {
high = mid - 1;
}
}
System.out.println("returning" + high);
return high;
}
I was asked to sort and search an array. The sorting the array was simple and my code worked but then whenever I try to call the binary search method it works for the first element in the array but gives me "-1" as a result
My full code is as follows:
public static void main(String[] args) {
int[] array = new int[5];
array[0] = 50;
array[1] = 40;
array[2] = 10;
array[3] = 20;
array[4] = 100;
sort(array, (array.length - 1));
for (int x = 0; x < array.length; x++) {
System.out.println(" " + array[x]);
}
System.out.println("");
System.out.println("Binary search (R): " + rBsearch(array, 0, (array.length), 20));
}
public static void sort(int[] a, int last) {
if (last > 0) {
int max = findMax(a, last);
swap(a, last, max);
sort(a, last - 1);
}
}
public static int rBsearch(int[] L, int low, int high, int k) {
int mid = (low + high) / 2;
if (low > high) {
return -1;
} else if (L[mid] == k) {
return mid;
} else if (L[mid] < k) {
return rBsearch(L, k, mid + 1, high);
} else {
return rBsearch(L, k, low, mid - 1);
}
}
public static int findMax(int[] arr, int last) {
int max = 0;
for (int i = 0; i <= last; i++) {
if (arr[i] > arr[max]) {
max = i;
}
}
return max;
}
public static void swap(int[] arr, int last, int max) {
int temp = arr[last];
arr[last] = arr[max];
arr[max] = temp;
}
You goofed up the binary search intervals
public static int rBsearch(int[] L, int low, int high, int k) {
int mid = (low + high) / 2;
if (low > high) {
return -1;
} else if (L[mid] == k) {
return L[mid];
} else if (L[mid] < k) {
return rBsearch(L, mid + 1, high, k);
} else {
return rBsearch(L, low, mid - 1, k);
}
}
You did a mistake in calling the rBsearch method in the following lines
Instead of
else if (L[mid] < k) {
return rBsearch(L, k, mid + 1, high);
} else {
return rBsearch(L, k, low, mid - 1);
}
You should use
else if (L[mid] < k) {
return rBsearch(L, mid + 1, high,k); //the order of the parameters
} else {
return rBsearch(L, low, mid - 1,k);
}
Easiest way is:
Convert you array to list: Arrays.asList(array)
For sort: Collections#sort
For search: Collections#binarySearch
See this
Take Array From User
Sort Array using Build-in Function of Java...
then Search Element using Binary Search....
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;
class BinarySearch
{
public static void main(String args[])
{
int array[];
Scanner input = new Scanner(System.in);
System.out.println("Enter number of elements:");
int Size_Of_Array = input.nextInt();
array = new int[Size_Of_Array];
System.out.println("Enter " + Size_Of_Array + " integers");
for (int counter = 0; counter < Size_Of_Array; counter++)
array[counter] = input.nextInt();
Arrays.sort(array);
System.out.println("Sorting Array is :-");
for (int counter = 0; counter < Size_Of_Array; counter++)
System.out.println(array[counter]);
System.out.println("Enter the search value:");
int Searching_item = input.nextInt();
int First_Index=0;
int Last_Index=Size_Of_Array-1;
int Middle_Index=(First_Index+Last_Index)/2;
while(First_Index <= Last_Index)
{
if(array[Middle_Index] < Searching_item)
{
First_Index=Middle_Index+1;
}
else if ( array[Middle_Index] == Searching_item )
{
System.out.println(Searching_item + " found at location " + (Middle_Index + 1) + ".");
break;
}
else
{
Last_Index = Middle_Index - 1;
}
Middle_Index = (First_Index + Last_Index)/2;
if ( First_Index > Last_Index )
{
System.out.println(Searching_item + " is not found.\n");
}
}
}
}
Result of BinarySearch