Related
I'm trying to run this implementation of binary search. I don't know why but it keeps giving me segfault error. I'm thinking the problem might be either the way I'm passing the array or there's something wrong with the recursive calls.
#include <stdio.h>
int hasBinarySearch(int *array, int low, int high, int element)
{
int mid = (low + (high-low)) / 2;
if (high>=low)
{
if (array[mid] == element)
{
return mid;
}
else if(array[mid]<element)
{
return hasBinarySearch(array, low, mid-1, element);
}
else
{
return hasBinarySearch(array, mid+1, high, element);
}
}
return 0;
}
int main(void)
{
int array[10] = {1,2,3,4,5,6,6,6,7,8};
hasBinarySearch(array, 0, 9, 2);
return 0;
}
I think that you have some misunderstanding about binary search. Read some article or book about it.
As #Claies commented, calculation of middle index is wrong.
It should be low + (high - low) / 2. Just think about the internal division of two points in mathematics.
Also, you have to fix the parameters on recursive calls like the code below.
#include <stdio.h>
int hasBinarySearch(int *array, int low, int high, int element)
{
int mid = low + (high - low) / 2; // changed
printf("%d %d\n", high, low);
if (high >= low)
{
if (array[mid] == element)
{
return mid;
}
else if (array[mid] < element)
{
return hasBinarySearch(array, mid + 1, high, element); // changed
}
else
{
return hasBinarySearch(array, low, mid - 1, element); // changed
}
}
return 0;
}
int main(void)
{
int array[10] = { 1,2,3,4,5,6,6,6,7,8 };
hasBinarySearch(array, 0, 9, 2);
return 0;
}
int mid = (low + (high-low)) / 2; // wrong formula
#paganinist good answer points out the flaws in OP's search method and with a fix.
Yet to dig deeper.
Even though some compilers might be able to "un-recurse" code (Example), recursion is not needed here. A simple loop will suffice.
Array sizes can approach near maximum or exceed the range of int in extreme cases.
For sizes in the high int range, the following is better. #Jonathan Leffler
// int mid = (low + high)/2; // could overflow
int mid = low + (high-low)/2; // better, will not overflow when low >= 0
To accommodate all array sizes, use size_t instead on int. This also handles sizes including those near and above INT_MAX.
Candidate solution that returns the address of the matching element or NULL if not found.
#include <stdlib.h>
#include <stdio.h>
int *BinarySearch_int(const int *array, size_t count, int key) {
while (count > 0) {
size_t mid = count / 2;
if (key > array[mid]) {
array += mid + 1;
count -= mid + 1;
} else if (key < array[mid]) {
count = mid;
} else {
return (int *) &array[mid];
}
}
return NULL;
}
Test code
bool BinarySearch_int_test(const int *array, size_t count, int key, bool target){
int *p = BinarySearch_int(array, count, key);
bool success = (p != NULL) == target && (p == NULL || *p == key);
printf("f(Array:%p count:%zu, key:%2d) --> ptr:%p value:%2d success:%d\n",
(void*) array, count, key, (void*) p, p ? *p : 0, success);
return success;
}
int main(void) {
int array[] = {10, 20, 30, 40, 50, 60};
size_t n = sizeof array / sizeof array[0];
for (size_t i = 0; i < n; i++) {
BinarySearch_int_test(array, n, array[i], 1);
}
BinarySearch_int_test(array, n, 0, 0);
for (size_t i = 0; i < n; i++) {
BinarySearch_int_test(array, n, array[i] + 1, 0);
}
}
Output
f(Array:0xffffcb90 count:6, key:10) --> ptr:0xffffcb90 value:10 success:1
...
f(Array:0xffffcb90 count:6, key:60) --> ptr:0xffffcba4 value:60 success:1
f(Array:0xffffcb90 count:6, key: 0) --> ptr:0x0 value: 0 success:1
...
f(Array:0xffffcb90 count:6, key:61) --> ptr:0x0 value: 0 success:1
mid's calculation simplifies to high / 2 because you've added and then subtracted the lower bound out again. It looks like you meant to add half the difference to the lower bound, but the division occurs too late. It should be low + (high-low) / 2. (This is a bit more complicated than (low + high) / 2 but avoids the integer-math problem mentioned elsewhere.)
I think that segfault is happening when high goes below low and gets too small and you fall off the beginning of the array.
And #paganinist is right about the upper and lower cases being backwards.
I have just learned my very first steps in C (I used to code in python) and as a such I'm facing great difficulty with the syntax, and as well as with binary search implementation. (I'm new to programming.)
So here's my code:
#include <stdlib.h>
#include <stdio.h>
#define size 1000
int binary_search(int array[size], int givenNumber) {
do {
int start = 0;
int end = size;
int middle = start + end / 2;
int left = size - 1;
int right = size + 1;
if (array[middle] == givenNumber) {
printf("location: %d, number: %i", middle, givenNumber);
return middle;
} else if (array[left] < givenNumber) {
int start = 0;
int end = array[left];
int middle = start + end / 2;
return middle;
} else if (array[right] > middle) {
int start = array[right];
int end = size;
int middle = start + end / 2;
return middle;
} else {
return -1;
break;
}
}
} while (int middle != givenNumber)
int main() {
int sorted_array[size];
for (int i = 0; i < size; i++) {
sorted_array[i] = i;
}
return binary_search(sorted_array, 349);
}
My problems are:
1 - when compiling, the error is something along the lines of "in while block "middle" isn't defined"
I have no clue on why the value isn't passing from the do block to the while block. Note that I added "return middle" to each if / else-if block, as I I thought it may help.
2- I'm not even quite sure if my own implementation of this binary search is correct. I have looked up how to implement it but I found it next to impossible to read the syntax, this is just to give a heads up.
UPDATE:
I have reconstructed the whole code according to the notes users have given in the answers below, and well, my algorithm is working and now it could find any number in any given array, however I'm unable to figure out a way to tell if the array doesn't have that givenNumber as it would get eventually stuck.
Here's an input/output:
int array[size] = {1,2,3,4,5,6,8,9,10,11,14,24,53,100};
function: binary_search(array, 24);
output: Location: 11, Number: 24
Which is pretty good, however if I enter a number which doesn't exist in the array, the loop continues to search endlessly (gets stuck in recursion)
here's the updated code:
#include <stdio.h>
#include <stdlib.h>
#define size 14
int start = 0;
int end = size -1;
int middle;
int left;
int right;
int binary_search(int array[size], int givenValue)
{
middle = (start + end) / 2;
printf("\nstart: %d \nend: %d \nmiddle: %d \n\n",start, end, middle);
do
{
if (start > end)
{
printf("item isn't found");
break;
return -1;
}
middle = (start+end)/2;
left = middle -1;
right = middle +1;
if (array[middle] == givenValue)
{
printf("Location: %d, Number: %d", middle, givenValue);
return middle;
break;
}
if(array[middle] > givenValue)
{
end = right;
return binary_search(array, givenValue);
}
if(array[middle] < givenValue)
{
start = left;
return binary_search(array, givenValue);
}
}
while (start <= end);
}
int main(void)
{
int array[size] = {1,2,3,4,5,6,8,9,10,11,14,24,53,100};
return binary_search(array, 24);
}
My condition is that if start is greater than end then the item doesn't exist, and it doesn't work at all because left/right keeps getting stuck at the same values (Run the code to know what I mean)
How do I fix this issue?
There are a number of issues:
The loop does not iterate. All parts of if/else have a return
massive amount of "shadowing" of variables
size is invariant so left/right are always set to the same thing
left and right should be started at 0 and size - 1 respectively
variables are used inconsistently (e.g. start is both an array index and an array value)
The function is more complex than it needs to be and has some extraneous variables
Your binary search algorithm is suspect
First and foremost, I'd recommend removing all "sub-scoped" variable declarations that shadow outer scoped ones (i.e. put all variables at the outermost scope).
Do this until you're more comfortable with these declarations. Learn more about the difference between:
variable declaration: int x;
variable declaration with initializer: int x = 5;
variable assignment: x = 5;
I've annotated your original function, created a test/diagnostic function and created a refactored function that passes the diagnostic test:
#include <stdio.h>
#define size 1000
int
binary_fixed(int *array, int givenNumber)
{
int left;
int right;
int middle;
int curval;
int retindex = -1;
left = 0;
right = size - 1;
while (left <= right) {
middle = (left + right) / 2;
curval = array[middle];
if (curval == givenNumber) {
retindex = middle;
break;
}
if (curval > givenNumber)
right = middle - 1;
else
left = middle + 1;
}
return retindex;
}
int
binary_search(int *array, int givenNumber)
{
int middle;
// NOTE/BUG: this does _not_ iterate
// NOTE/BUG: _massive_ amount of "shadowing" of variables
// NOTE/BUG: size is _invariant_ so left/right are _always_ set to the
// same thing
// NOTE/BUG: left and right should start at 0 and size - 1 respectively
// NOTE/BUG: variables are used _inconsistently_ (e.g. start is both
// an array index and an array _value_)
do {
int start = 0;
int end = size;
int middle = start + end / 2;
int left = size - 1;
int right = size + 1;
if (array[middle] == givenNumber) {
printf("location: %d, number: %i\n", middle, givenNumber);
return middle;
}
else if (array[left] < givenNumber) {
int start = 0;
int end = array[left];
int middle = start + end / 2;
return middle;
}
else if (array[right] > middle) {
int start = array[right];
int end = size;
int middle = start + end / 2;
return middle;
}
else {
return -1;
}
} while (middle != givenNumber);
printf("BADRETURN givenNumber=%d\n", givenNumber);
}
int sorted_array[size];
void
test(const char *who,int (*fnc)(int *,int))
{
int i;
int r;
for (i = 0; i < size; i++) {
r = fnc(sorted_array, i);
if (r != i) {
printf("ERROR -- EXPECTED: %d ACTUAL: %d (from %s)\n", i, r, who);
// break;
}
}
}
int
main()
{
for (int i = 0; i < size; i++) {
sorted_array[i] = i;
}
//test("ORIGINAL",binary_search);
test("FIXED",binary_fixed);
return 0;
}
UPDATE:
Since you're coming from python, here are a few points that may help with your understanding.
Arrays are passed to functions as pointers, so in the function argument list, int *array is equivalent. Doing int array[size] is an advanced technique. Avoid it for now. In C, you can't do array.count as you can in python. So, for now, pass the count as an additional argument.
Pointers are something that python doesn't have, so you'll have to learn about how to use them. Once you get the hang of them, they are quite powerful and can make code run quite fast.
In C [and most languages except python [and php]], the default scope is global. It's the reverse of python. In python, unless you specify global x, then x is private to the function. In other languages, to have x be local to the function, you have to declare it at function scope.
In C, all variables must be declared somewhere: global scope, function scope [or a block scope within a function], or as an argument. And, each declaration must specify an explicit type. There is no equivalent of javascript's declaration of var x. After that, x could be either a string or a value depending upon what you set it to: (e.g. x = 23 or x = "abc")
In C, x must be given a type such as: int x; or double x; or int *x; or char *x.
Here is your revised code with annotations:
#include <stdio.h>
#include <stdlib.h>
// NOTE: this is hardwired
#define size 14
// NOTE: this is _global_ scope -- while not absolutely wrong, using function
// scope below is faster/better and provides better isolation -- this doesn't
// scale as well
int start = 0;
int end = size - 1;
int middle;
int left;
int right;
// NOTE: in C, using "int *array" is equivalent [and in many cases preferred]
// NOTE: the array count should be passed in as a separate argument
int
binary_search(int array[size], int givenValue)
{
// NOTE: this is _function_ scope
// NOTE: this calc of middle is extraneous because it is recalculated
// below
middle = (start + end) / 2;
printf("\nstart: %d \nend: %d \nmiddle: %d \n\n", start, end, middle);
// NOTE/BUG: this function combines _both_ a loop implementation and a
// recursive implementation -- we have to pick one or the other as trying
// to do both messes things us -- the recursion is broken [see below]
// NOTE: this loop checks start vs end _twice_ in the loop -- it only
// needs to check in one place -- convert this to "while (start <= end) {"
// instead of a "do {...} while (whatever);" loop [which is usually not
// as good]
do {
if (start > end) {
printf("item isn't found");
break;
// NOTE/BUG: this return will _never_ be executed because we
// break out of the loop and what is worse we'll return an
// unknown/undefined value because
return -1;
}
middle = (start + end) / 2;
// NOTE/BUG: these are reversed
left = middle - 1;
right = middle + 1;
if (array[middle] == givenValue) {
printf("Location: %d, Number: %d", middle, givenValue);
return middle;
break;
}
// NOTE/BUG: these recursive calls do nothing because they do _not_
// further limit the scope and cause infinite recursion -- to make
// a recursive version work, start/end would need to be arguments:
// return binary_search(array,givenValue,start,end)
// and we shouldn't loop -- the recursive calls just aren't needed
// NOTE/BUG: the tests here are broken -- they are the reverse of
// the correct ones
if (array[middle] > givenValue) {
end = right;
return binary_search(array, givenValue);
}
if (array[middle] < givenValue) {
start = left;
return binary_search(array, givenValue);
}
// NOTE/BUG: this extra test is extraneous and would be done too late
// if the array size was zero -- a case that isn't handled here
} while (start <= end);
// NOTE/BUG: when we break out of the loop, we need to return _some_ value
// here -- this would be flagged by the compiler using the -Wall option
}
int
main(void)
{
int array[size] = { 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 14, 24, 53, 100 };
// NOTE/BUG: the return value from main can only handle numbers 0-255
// better to print the return value
return binary_search(array, 24);
}
Here is a working version of your revised code.
The loop is now a simple while. The function takes a separate count argument. It loops instead of recurses. The reversed if logic has been fixed. Again, a diagnostic test has been added.
#include <stdio.h>
#include <stdlib.h>
int
binary_search(int *array, int size, int givenValue)
{
// NOTE: this is _function_ scope
int start = 0;
int end = size - 1;
int middle;
int left;
int right;
int match_index;
// assume failure
match_index = -1;
// NOTE: this calc of middle is extraneous because it is recalculated
// below
middle = (start + end) / 2;
printf("\nstart: %d \nend: %d \nmiddle: %d \n\n", start, end, middle);
while (start <= end) {
middle = (start + end) / 2;
left = middle - 1;
right = middle + 1;
if (array[middle] == givenValue) {
printf("Location: %d, Number: %d\n", middle, givenValue);
match_index = middle;
break;
}
if (array[middle] > givenValue) {
end = left;
}
if (array[middle] < givenValue) {
start = right;
}
}
if (match_index < 0)
printf("match not found -- givenValue=%d\n",givenValue);
return match_index;
}
int
main(void)
{
int array[] = { 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 14, 24, 53, 100 };
int count = sizeof(array) / sizeof(array[0]);
int curidx;
int valwant;
int match;
printf("%d\n",binary_search(array, count, 24));
// run diagnostic on all values
for (curidx = 0; curidx < count; ++curidx) {
// get value to search for
valwant = array[curidx];
match = binary_search(array,count,valwant);
if (match != curidx) {
printf("fault: curidx=%d valwant=%d match=%d\n",
curidx,valwant,match);
}
}
// test lower range failure
valwant = array[0] - 1;
match = binary_search(array,count,valwant);
if (match >= 0)
printf("fault: valwant=%d match=%d\n",valwant,match);
// test upper range failure
valwant = array[count - 1] + 1;
match = binary_search(array,count,valwant);
if (match >= 0)
printf("fault: valwant=%d match=%d\n",valwant,match);
return 0;
}
A typical binary search implementation would either loop or recurse until the number is found. The naive recursive code is something like this:
#include <stdio.h>
#define size 1000
int binary_search(int array[size], int givenNumber, int start, int end) {
int middle;
middle = (start + end) / 2;
if (start > end)
return -1;
if (array[middle] == givenNumber) {
printf("location: %d, number: %i", middle, givenNumber);
return middle;
} else if (array[middle] < givenNumber) {
return binary_search(array, givenNumber, middle + 1, end);
} else { // if (array[middle] > givenNumber)
return binary_search(array, givenNumber, start, middle - 1);
}
}
int main() {
int sorted_array[size];
for (int i = 0; i < size; i++) {
sorted_array[i] = i * 2;
}
if (binary_search(sorted_array, 349, 0, size - 1) < 0) {
printf("value not found\n");
}
if (binary_search(sorted_array, 34, 0, size - 1) < 0) {
printf("value not found\n");
}
}
Notice in the recursion we call binary_search each time with a new start and end range based on the sorted array and the provided input in givenNumber.
You can't declare a variable inside a while statement. Move it to the top of your function.
You have a misplaced curly brace in your code.
Try this:
#include <stdlib.h>
#include <stdio.h>
#define size 1000
int binary_search(int array[size], int givenNumber) {
int middle;
do {
int start = 0;
int end = size;
int middle = start + end / 2;
int left = size - 1;
int right = size + 1;
if (array[middle] == givenNumber) {
printf("location: %d, number: %i", middle, givenNumber);
return middle;
} else if (array[left] < givenNumber) {
int start = 0;
int end = array[left];
int middle = start + end / 2;
return middle;
} else if (array[right] > middle) {
int start = array[right];
int end = size;
int middle = start + end / 2;
return middle;
} else {
return -1;
}
} while (middle != givenNumber);
}
int main() {
int sorted_array[size];
for (int i = 0; i < size; i++) {
sorted_array[i] = i;
}
return binary_search(sorted_array, 349);
}
I am doing a project for my C class. We are going to find the value in an ascending array with 10 distinctive numbers, then search the value users wanna and return the index of the searching number. The first method is called Linear Search which compare each element in the array to the value user wanted. The second method is called Binary, which you take the middle index compare with the searching value. If List[middle] = target element then return the variable middle which is the index of the element. In the case that target element is greater than List[Middle], then continue the process on the right half of the array. If it is lesser, then continue the same process on the left half of the array. The process of halving is done only until the ‘Left’ index variable is less than or equal to the ‘Right’ index variable. In case the target element is not found , -1 is returned.
#include<stdio.h>
int main()
{
int array[10];
int i = 0,value;
printf("Please enter 10 distinctive postive numbers with ascending order.");
for(i;i<10;i++)
{
scanf("%d",&array[i]);
}
printf("What value are you seaching for?");
scanf("%d",value);
printf("searchLinear(value,*array[10],10)");
return 0;
}
int searchLinear(int s,int *list[10],int n){
list[n];
int i = 0;
for(i;i<n;i++)
{
if(s == *list[i])
return *list[i];
}
if(i = n)
return -1;
}
int searchBinary(int s, int *list[10],int n) {
list[n];
int i,left,right,middle;
left = 0;
right = n-1;
for(i = 0;i<n/2;i++)
{
middle = (left + right)/2;
if(*list[middle] > s)
right = middle;
else if(*list[middle] < s)
left = middle;
else if(*list[middle] = s)
return *list[middle];
if(left == right)
return -1;
}
}
This is my code, looks like it runs into an infinite loop. How can I fix it?
The corrected code is
#include<stdio.h>
int searchLinear(int s,int list[],int n);
int searchBinary(int s, int list[],int n); //you need to give forward declaration of funcs
int main()
{
int array[10];
int i = 0,value;
printf("Please enter 10 distinctive postive numbers with ascending order.");
for(i;i<10;i++)
{
scanf("%d",&array[i]);
}
printf("What value are you seaching for?");
scanf("%d",&value); //you missed & here
printf("%d",searchBinary(value,array,10));
return 0;
}
int searchLinear(int s,int list[],int n){ // you can use this format of arguments
//list[n]; //what did you wanted to do with this line
int i = 0;
for(i;i<n;i++)
{
if(s == list[i])
return i; //return index not value
}
if(i = n)
return -1;
}
int searchBinary(int s, int list[],int n){
//list[n];
int i,left,right,middle;
left = 0;
right = n-1;
for(i = 0;i<n/2;i++)
{
middle = (left + right)/2;
if(left > right) //you have to check left>right, instead of left==right
return -1;
if(list[middle] > s)
right = middle-1;
else if(list[middle] < s)
left = middle+1;
else if(list[middle] == s) //== is used for comparision
return middle;
}
}
Observe the corrections in comments
First time posting here. I recently implemented Binary Search but sometimes my outputs will return a giant negative number instead. Now my first thought is that I'm printing a number where my pointer is pointing at a random memory location. Can someone help me with the logic and how I can improve my code?
#include <stdio.h>
#include <stdlib.h>
int binarysearch(int *array, int size, int target);
int main() {
int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, 8, 15));
return 0;
}
int binarysearch(int *array, int size, int target) {
int mid;
mid = size / 2;
if (size < 1) {
return -1;
}
if (size == 1) {
return array[0];
}
if (target == array[mid]) {
return target;
} else
if (target < array[mid]) {
binarysearch(array, mid, target);
} else{
binarysearch(array + mid, size - mid, target);
}
}
For starters you call the function with an invalid number of elements in the array that has only 6 elements.
int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, 8, 15));
^^^
Also this snippet
if (size == 1) {
return array[0];
}
is incorrect. It is not necessary that the first element is equal to target.
This statement
binarysearch(array + mid, size - mid, target);
has to be written like
binarysearch(array + mid + 1, size - mid - 1, target);
And at last the function has undefined behavior because it returns nothing in these cases
if (target < array[mid]) {
binarysearch(array, mid, target);
} else{
binarysearch(array + mid, size - mid, target);
}
You need to write
if (target < array[mid]) {
return binarysearch(array, mid, target);
} else{
return binarysearch(array + mid, size - mid, target);
}
And two words about the programming style. It is better to name the function either like binary_search or like binarySearch or at last like BinarySearchthan like binarysearch.
In general it is not a good design of the function. Imagine that the array has an element with the value -1. How will you determine whether this element is present in the array or is absent?
Usually such functions return pointer to the target element in case if it is found or NULL pointer otherwise.
Here is a demonstrative program that shows how this approach can be implemented.
#include <stdio.h>
int * binary_search( const int *a, size_t n, int target )
{
if ( n == 0 ) return NULL;
size_t middle = n / 2;
if ( a[middle] < target )
{
return binary_search( a + middle + 1, n - middle - 1, target );
}
else if ( target < a[middle] )
{
return binary_search( a, middle, target );
}
return a + middle;
}
int main(void)
{
int array[] = { 1, 2, 3, 4, 5, 6 };
const size_t N = sizeof( array ) / sizeof( *array );
for ( int i = 0; i < 8; i++ )
{
int *target = binary_search( array, N, i );
if ( target )
{
printf( "%d is found at position %d\n", *target, ( int )(target - array ) );
}
else
{
printf( "%d is not found\n", i );
}
}
return 0;
}
The program output is
0 is not found
1 is found at position 0
2 is found at position 1
3 is found at position 2
4 is found at position 3
5 is found at position 4
6 is found at position 5
7 is not found
By the way according to the C Standard function main without parameters shall be declared like
int main( void )
You call binarysearch(array, 8, 15)) but your array has only 6 entries.
Here is how to compute the proper size automatically:
int main(void) {
int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, sizeof(array) / sizeof(array[0]), 15));
return 0;
}
Note that your function binarysearch has problems too:
Returning the array entry is bogus, what do you return if the target is less than the first entry? -1 is not necessarily less than the first entry.
You are supposed to return the index into the array with the entry if found and -1 if not found.
When you recurse, you do not return the value from these recursive calls: you should compile with warnings enabled (for example: gcc -Wall -W) and look at all the helpful diagnostic messages the compiler produces.
Here is a modified version:
int binarysearch(const int *array, int size, int target) {
int a, b;
for (a = 0, b = size; a < b;) {
int mid = a + (b - a) / 2;
if (target <= array[mid]) {
b = mid;
} else {
a = mid + 1;
}
}
// a is the offset where target is or should be inserted
if (a < size && target == array[a])
return a;
else
return -1;
}
Notes:
Computing mid = (a + b) / 2; would be potentially incorrect for large sizes as there may be an arithmetic overflow. mid = a + (b - a) / 2; does not have this problem since a < b.
The time-complexity is O(Log N), and for a given size, the function performs the same number of steps for all target values.
If the array contains multiple identical values equal to target, the index returned by binarysearch is that of the matching entry with the lowest index.
You could make this problem easier by using the bsearch function offered by the <stdlib.h> library.
Something like this:
#include <stdio.h>
#include <stdlib.h>
int cmpfunc(const void * a, const void * b);
int
main(void) {
int array[] = {1, 2, 3, 4, 5, 6};
size_t n = sizeof(array)/sizeof(*array);
int *item;
int key = 15;
item = bsearch(&key, array, n, sizeof(*array), cmpfunc);
if (item != NULL) {
printf("Found item = %d\n", *item);
} else {
printf("Item = %d could not be found\n", key);
}
return 0;
}
int
cmpfunc(const void * a, const void * b) {
return (*(int*)a > *(int*)b) - (*(int*)a < *(int*)b);
}
If you don't want to use bsearch, then this method will be fine also:
#include <stdio.h>
#include <stdlib.h>
#define BSFOUND 1
#define BS_NOT_FOUND 0
int cmpfunc(const void * a, const void * b);
int binary_search(int A[], int lo, int hi, int *key, int *locn);
int
main(void) {
int array[] = {1, 2, 3, 4, 5, 6};
size_t n = sizeof(array)/sizeof(*array);
int key = 4, locn;
if ((binary_search(array, 0, n, &key, &locn)) == BSFOUND) {
printf("Found item = %d\n", array[locn]);
} else {
printf("Item = %d cound not be found\n", key);
}
return 0;
}
int
binary_search(int A[], int lo, int hi, int *key, int *locn) {
int mid, outcome;
if (lo >= hi) {
return BS_NOT_FOUND;
}
mid = lo + (hi - lo) / 2;
if ((outcome = cmpfunc(key, A+mid)) < 0) {
return binary_search(A, lo, mid, key, locn);
} else if(outcome > 0) {
return binary_search(A, mid+1, hi, key, locn);
} else {
*locn = mid;
return BSFOUND;
}
}
int
cmpfunc(const void * a, const void * b) {
return (*(int*)a > *(int*)b) - (*(int*)a < *(int*)b);
}
Based on the following definition found here
Returns an iterator pointing to the
first element in the sorted range
[first,last) which does not compare
less than value. The comparison is
done using either operator< for the
first version, or comp for the second.
What would be the C equivalent implementation of lower_bound(). I understand that it would be a modification of binary search, but can't seem to quite pinpoint to exact implementation.
int lower_bound(int a[], int lowIndex, int upperIndex, int e);
Sample Case:
int a[]= {2,2, 2, 7 };
lower_bound(a, 0, 1,2) would return 0 --> upperIndex is one beyond the last inclusive index as is the case with C++ signature.
lower_bound(a, 0, 2,1) would return 0.
lower_bound(a, 0, 3,6) would return 3;
lower_bound(a, 0, 4,6) would return 3;
My attempted code is given below:
int low_bound(int low, int high, int e)
{
if ( low < 0) return 0;
if (low>=high )
{
if ( e <= a[low] ) return low;
return low+1;
}
int mid=(low+high)/2;
if ( e> a[mid])
return low_bound(mid+1,high,e);
return low_bound(low,mid,e);
}
Here are the equivalent implementations of upper_bound and lower_bound. This algorithm is O(log(n)) in the worst case, unlike the accepted answer which gets to O(n) in the worst case.
Note that here high index is set to n instead of n - 1. These functions can return an index which is one beyond the bounds of the array. I.e., it will return the size of the array if the search key is not found and it is greater than all the array elements.
int bs_upper_bound(int a[], int n, int x) {
int l = 0;
int h = n; // Not n - 1
while (l < h) {
int mid = l + (h - l) / 2;
if (x >= a[mid]) {
l = mid + 1;
} else {
h = mid;
}
}
return l;
}
int bs_lower_bound(int a[], int n, int x) {
int l = 0;
int h = n; // Not n - 1
while (l < h) {
int mid = l + (h - l) / 2;
if (x <= a[mid]) {
h = mid;
} else {
l = mid + 1;
}
}
return l;
}
The actual C++ implementation works for all containers. You can find it here.
lower_bound is almost like doing a usual binary search, except:
If the element isn't found, you return your current place in the search, rather than returning some null value.
If the element is found, you search leftward until you find a non-matching element. Then you return a pointer/iterator to the first matching element.
Yes, it's really that simple. :-)
I know that this is a very old post. However, I was working on a problem and I came across this post. I would like to add my iterative version for the problem which is an extension of the last answer. I checked this with the test cases I could think of. I've attached my code in C#.
This code was working for all ranges. However, the range should be within the first index to the last index+1. If the array is of size N and considering range as [0,N] the search space will be within [0,N). I know that's pretty obvious but it helped me checking some edge cases.
static int lower_bound(int[] a, int lo,int hi, int x)
{
while (lo < hi)
{
int mid = lo + (hi-lo) / 2;
if(a[mid]==x)
{
/*when there is a match, we should keep on searching
for the next same element. If the same element is not
found, mid is considered as the answer and added to 'hi'
Finally 'hi' is returned*/
if(a[mid-1]!=x)
{
hi=mid;
break;
}
else
hi=mid-1;
}
else if(a[mid]>x)
hi=mid-1;
else
lo=mid+1;
}
//if element is not found, -1 will be returned
if(a[hi]!=x)
return -1;
return hi;
}
static int upper_bound(int[] a, int lo,int hi, int x)
{
int temp=hi;
while (lo < hi)
{
int mid = lo + (hi-lo) / 2;
if(a[mid]==x)
{
/*this section make sure that program runs within
range [start,end)*/
if(mid+1==hi)
{
lo=mid;
break;
}
/*when there is a match, we should keep on searching
for the next same element. If the same element is not
found, mid is considered as the answer and added to
'lo'. Finally 'lo' is returned*/
if(a[mid+1]!=x)
{
lo=mid;
break;
}
else
lo=mid+1;
}
else if(a[mid]>x)
hi=mid-1;
else
lo=mid+1;
}
//if element is not found, -1 will be returned
if(a[lo]!=x)
return -1;
return lo;
}
Here is a test case that I used:
Array(a) : 1 2 2 2 2 5 5 5 5
size of the array(a) : 9
Considering search element as 2:
upper_bound(a,0,9,2)=4, lower_bound(a,0,9,2)=1
Considering search element as 5:
upper_bound(a,0,9,2)=8, lower_bound(a,0,9,2)=5
Considering search element as 1:
upper_bound(a,0,9,2)=0, lower_bound(a,0,9,2)=0
Considering search element as 5:
upper_bound(a,5,9,2)=8, lower_bound(a,5,9,2)=5
The lower_bound and upper_bound functions in python would be implemented as follows:
def binLowerBound(a, lo, hi, x):
if (lo > hi):
return hi
mid = (lo + hi) / 2;
if (a[mid] == x):
return binLowerBound(a, lo, mid-1, x)
elif (a[mid] > x):
return binLowerBound(a, lo, mid-1, x)
else:
return binLowerBound(a, mid+1, hi, x)
def binHigherBound(a, lo, hi, x):
if (lo > hi):
return lo
mid = (lo + hi) / 2;
if (a[mid] == x):
return binHigherBound(a, mid+1, hi, x)
elif (a[mid] > x):
return binHigherBound(a, lo, mid-1, x)
else:
return binHigherBound(a, mid+1, hi, x)
C++ Implementation
int binary_search_lower_bound(vector<int>& array, int target) {
int lo = 0, hi = (int)array.size();
int mid;
while(lo < hi) {
mid = lo + ((hi - lo) >> 1);
int val = array[mid];
if (target <= val)//array[mid])
hi = mid;
else
lo = mid + 1;
}
return lo;
}
Edit: Fixed bug for non-existing value.
int lowerBound (int *a, int size, int val) {
int lo = 0, hi = size - 1;
while (lo < hi) {
int mid = lo + (hi - lo)/2;
if (a[mid] < val)
lo = mid + 1;
else
hi = mid;
}
return lo;
}
Example if this is the given array
1 2 3 3 4
and different values of x is
3 then firstOccurance will be 2 and lastOccurance will be 3
2 then firstOccurance will be 1 and lastOccurance will be 1
10 then firstOccurance will be -1 and lastOccurance will be -1
int firstOccurance(vector<int>& arr, int x){
int low = 0;
int high = arr.size();
int ans=-1;
while(low<=high){
int mid = (low+high)/2;
if(arr[mid]==x) ans=mid;
if(arr[mid]>=x) high=mid-1;
else low = mid+1;
}
return ans;
}
int lastOccurance(vector<int>& arr, int x){
int low = 0;
int high = arr.size();
int ans=-1;
while(low<=high){
int mid = (low+high)/2;
if(arr[mid]==x) ans=mid;
if(arr[mid]<=x) low=mid+1;
else high = mid-1;
}
return ans;
}
I know this is a very old post with a lot of answers already but I came across this problem as well and needed a generic solution so I used manish_s answer to adapt the gnu stdlib bsearch function. In case anyone needs it:
size_t myBsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
__compar_fn_t __compar)
{
size_t __l, __u, __idx;
const void *__p;
int __comparison;
__l = 0;
__u = __nmemb;
while (__l < __u)
{
__idx = (__l + __u) / 2;
__p = (void *)(((const char *)__base) + (__idx * __size));
__comparison = (*__compar)(__key, __p);
if (__comparison <= 0)
__u = __idx;
else if (__comparison > 0)
__l = __idx + 1;
}
return __l;
}