Why is this binary search giving me an infinite loop? - c

I am trying to do a binary search. I really can't think of why I am getting an infinite loop? Is is because I ignored the null value somewhere? The value, values[], and n are being provided by a different file, and they are written by someone else, and are, for the purposes of this question, perfectly coded.
bool search(int value, int values[], int n)
{
int upper_bound = n - 1;
int lower_bound = 0;
int middle = (upper_bound + lower_bound) / 2;
while (lower_bound <= upper_bound)
{
if (values[middle] == value)
{
return true;
}
else if (values[middle] > value)
{
upper_bound = middle - 1;
}
else if (values[middle] < value)
{
lower_bound = middle + 1;
}
else
{
return false;
}
}
return false;
}
Thank you all so much.

You need to calculate the value of middle inside the while loop:
while (lower_bound <= upper_bound){
int middle = (upper_bound + lower_bound) / 2;
...
}
As the value of middle should change every time you are changing the value of either lower_bound or upper_bound.

the middle value is fixed. It is not changing as the values of upper_bound and lower_bound are changing.

Related

Binary search in C always returns false, even when value is contained in sorted array [duplicate]

This question already has an answer here:
C recursive function won't return true
(1 answer)
Closed 5 years ago.
New to programming. Trying to implement binary search in C but unfortunately it isn't working properly. my function always returns false even when the value is in the array. New to programming. please help.
Function takes following inputs:
"value" - integer value to be found in array.
"values" - the sorted array.
"n" - number of integers in array.
bool search(int value, int values[], int n)
{
// recursive implementation of binary search
if (n % 2 == 0)
{
search_even(value, values, n);
}
else
{
search_odd(value, values, n);
}
return false;
}
bool search_even(int value, int values[], int n)
{
// binary search
if (n <= 0)
{
return false;
}
// check middle of array
else if (value == values[n/2])
{
return true;
}
// search left half of sorted array
else if (value < values[n/2])
{
int less_than_arr[n/2];
for (int i = 0; i < n/2; i++)
{
less_than_arr[i] = values[i];
}
search(value, less_than_arr, n/2);
}
// search right half of sorted array
else if (value > values[n/2])
{
int more_than_arr[(n/2) - 1];
for (int i = 0; i < (n/2) - 1; i++)
{
more_than_arr[i] = values[i + 1 + n/2];
}
search(value, more_than_arr, n/2);
}
return false;
}
bool search_odd(int value, int values[], int n)
{
// binary search
if (n <= 0)
{
return false;
}
// check middle of array
else if (value == values[n/2])
{
return true;
}
// search left half of sorted array
else if (value < values[n/2])
{
int less_than_arr[n/2];
for (int i = 0; i < n/2; i++)
{
less_than_arr[i] = values[i];
}
search(value, less_than_arr, n/2);
}
// search right half of sorted array
else if (value > values[n/2])
{
int more_than_arr[n/2];
for (int i = 0; i < n/2; i++)
{
more_than_arr[i] = values[i + 1 + n/2];
}
search(value, more_than_arr, n/2);
}
return false;
}
You (recursively) call search functions but never return the value computed by the calls. Look at:
bool search(int value, int values[], int n)
{
// recursive implementation of binary search
if (n % 2 == 0)
{
search_even(value, values, n);
}
else
{
search_odd(value, values, n);
}
return false;
}
This function always return false.
You need at least to replace search*(...) with return search*(...), so that value determined at the leaves of the calls is transmitted back to the original (first) call.
Jean-Baptiste has already pointed out the obvious error in your function, but there are more issues:
You create local copies of the subarrays to search. This is not necessary and will make binary search slower than linear search.
Copying data is usually only necessary when you want to modify it, but retain the original state. Your search function only inspects the data. Strictly speaking, your argument int values[] should probably be const int values[] to reflect that fact.
In C, you must pass the pointer to the first element and the length of an array. Arrays decay into pointers to their first element, so the following:
int val[4] = {2, 4, 7, 12};
search(3, val, 4);
already does that.
But here's a useful idiom: If you want to pass in the subarray that starts at position k, use:
search(3, val + k, 4 - k);
More generally, you can pass the array slice [lo, hi), where lo is the zero-based inclusive lower bound and hi is the exclusive upper bound as:
search(3, val + lo, hi - lo);
In the called function, the indices will then be [0, hi - lo); the original array offset is lost.
Further, you don't need to distinguish the two cases of odd n and even n if you calculate the size of the right-hand array as difference between the original size minus the size of the left-hand array plus one:
mid == n / 2
left = [0, mid)
right = [mid + 1, n)
With this, your recursive binary search function will become:
bool search(int value, const int values[], int n)
{
if (n == 0) return false;
if (value < values[n / 2]) {
return search(value, values, n / 2);
}
if (value > values[n / 2]) {
return search(value, values + n / 2 + 1, n - n / 2 - 1);
}
return true;
}

binary search - if I add or subract "1" from the middle of the list, do I get the first number on the left of the middle one or a numerical value?

My doubt occurs inside the while loop. What am I doing when I add "1" to the minimum and maximum of the list -- am I moving to the left/right of the numbers on the list or changing values numerically? Thanks!
bool search(int value, int values[], int n) {
if (n < 0) {
return false;
}
// beginning and final portions
int min = 0;
int max = n - 1;
// middle variable
int mid = n / 2;
// this massive number will be useful to guarantee that the search function
// can handle incredibly large arrays
const int MAX = 65536;
while (n > 0) {
if (value > value[middle]) {
min = middle + 1;
} else
if (value < value[middle]) {
max = middle - 1;
} else
if (value == value[middle]) {
return true;
}
}
}
Your function is broken in many respects:
it does not implement binary search
MAX is not massive, and it is not even used anywhere
middle is undefined, and it is not modified in the loop.
value > value[middle] should probably be value > values[mid]...
Here is a simple correct implementation (borrowed from Matt Timmermans):
bool search(int value, int values[], size_t n) {
size_t pos = 0;
size_t limit = n;
while (pos < limit) {
size_t middle = pos + ((limit - pos) >> 1);
if (values[middle] < value)
pos = middle + 1;
else
limit = middle;
}
return pos < n && values[pos] == value;
}
let's think your value array is like: 1 2 5 6 9 so min=1,max=9,mid=5; now suppose your value is 7 then if (value > value[middle]){min = middle + 1;} this block will be active.
Now look as we are sure that our value is greater than middle value so we can increase our minimum value to be (mid+1)th index of value array.
same applies when it is smaller. so you are actually moving min/max index of value array. Hope that helps

how to fix- Control may reach end of non-void function

I meet problem during cs50 class, I have to write binary search function.
When trying to run code this message appear: control may reach end of non-void function. I tried to fix by adding at last line return false but this makes output always false. Please give me some tips.
Here is my code:
bool search_r(int value, int values[], int l, int r) {
int v = values[(l + r) / 2];
int right = r;
int left = l;
if ((l + r) / 2 > 0) {
if (v == value) {
return true;
} else
if (v > value) {
right = ((l + r) / 2);
search_r(value, values, left, right);
} else
if (v < value) {
left = ((l + r) / 2);
search_r(value, values, left, right);
}
} else {
return false;
}
}
Your function has several problems:
You must return the values from the recursive calls to search_r(). This error is causing the warning as the function does not have a return statement after the nested if statements. Making it return false; at the end is incorrect as the recursive call should return true if the value is found.
(l + r) / 2 may overflow if l or r is very large. The result would be incorrect in this case. The correct way to compute the middle index is l + (r - l) / 2.
The test for termination is not (l + r) / 2 > 0, which only tests if the middle index is > 0. Instead use l < r, ie. if the range is not empty, l being included and r excluded.
The test if (v < value) is redundant, you already tested for v == value and v > value.
Using l as a variable name is somewhat confusing as it is visually very similar to 1, especially for fixed pitch fonts used for code.
Here is a corrected version:
bool search_r(int value, int values[], int left, int right) {
if (left < right) {
int middle = left + (right - left) / 2;
int v = values[middle];
if (v == value) {
return true;
} else
if (v > value) {
return search_r(value, values, left, middle);
} else {
return search_r(value, values, middle + 1, right);
}
} else {
return false;
}
}
Finally, the function can be implemented as a loop instead of using recursion. The compiler is likely to generate the same code since the recursion is terminal, but some people find one way more intuitive than the other:
bool search_r(int value, int values[], int left, int right) {
while (left < right) {
int middle = left + (right - left) / 2;
int v = values[middle];
if (v == value) {
return true;
} else
if (v > value) {
right = middle;
} else {
left = middle + 1;
}
}
return false;
}
In both cases, the function should be called this way, where length is the number of elements of array.
bool found = search_r(value, array, 0, length);
The last else is not necessary, if you simply return false it will do exactly what you want. But you should probably return true inside the if branch. Or make the function not return at all, since you are not using the return value anyway, and if it's always false it's not very useful anyway.
Your function:
bool search_r(int value, int values[], int left, int right)
Indicates that a bool will be returned. I think #chqrlie has an excellent response to this.
You should have a some default value returned that is not affected by any loops or conditionals in case those aren't met.
Consider the condition that the if condition is not satisfied and the program finishes without giving a return value. Now it is impossible because of your else condition.But the compiler does not know that and hence wants to make sure that the function returns a value since it is a non-void function.
Removing the else condition and simply adding
return false;
at the end of your program will solve the problem.

Divide and Conquer in C, may reach end of non-void function

I am trying to get this divide and conquer to work, but the compiler is giving me:
control may reach end of non-void function
I have read through similar scenarios, and understand the error implies the program might run forever without a return. I have reviewed some scenarios, which were resolved by using "else" instead of "if else" (as you should to begin with). However, that didn't help.
I am aware that using a do while loop and return in this scenario is redundant, I was fiddling with it in hopes to trick the compiler.
Where is the error?
bool search(int value, int values[], int n)
{
int sorted = 0;
int min = 0;
int max = n;
int mid = n / 2;
do
{
//mid is value
if (value == values[mid])
{
printf("value found!");
sorted = 1;
return 1;
}
//search right
else if (values[mid] < value)
{
min = mid + 1;
mid = (max - mid) / 2 ;
}
//search left
else if (values[mid] > value)
{
max = mid - 1;
mid = (max - mid) / 2;
}
// DNE
else
{
printf("value not found");
sorted = 1;
return 0;
}
}
while(sorted == 0);
}
Every branch of code should have a return if function suppose to return a value.
In your case after while you have to put a return. How ever, Your logic is also slightly wrong. In your code there is not any need of sorted variable and the terminating condition is also wrong as well as the way of calculating mid is also wrong. Don't worry here is your updated code:
bool search(int value, int values[], int n)
{
//int sorted = 0;
int min = 0;
int max = n;
int mid = n / 2; // S1
do
{
//mid=(max+min)/2; // S2
//mid is value
if (value == values[mid])
{
//printf("value found!");
//sorted = 1;
return 1;
}
//search right
else if (values[mid] < value)
{
min = mid + 1;
mid = (max + min) / 2 ; // S3
}
//search left
else if (values[mid] > value)
{
max = mid - 1;
mid = (max + min) / 2; //S4
}
// DNE
else
{
//printf("value not found");
//sorted = 1;
return 0;
}
}
while(min!=max);
return 0;
}
So if your function is returning 1 it mean value found otherwise value doesn't found.
you also can comment S1, S3 and S4 and uncomment S2 for minimum line of code.
And the way of finding mid will be mid=(max+min)/2.
Ignoring other problems in your code (the loop will never terminate under certain conditions although I didn't study it too closely), let's just look at why the compiler complains, because it's quite interesting.
Your compiler complains about that you don't have a return at the end of the function (pretty much what we can read from the warning message) after the while loop. You loop runs:
while(sorted == 0);
And everywhere you change sorted, you do this:
sorted = 1;
return X;
So it is pretty obvious to you and me that the while condition will always be true and you won't fall out of the while loop and need a return after it. Every time you make the while condition not true, you also return immediately. But the compiler doesn't know that. It probably could figure it out with a little bit more effort, but it can never be written to know in all cases and you wouldn't accept a compiler that slow anyway. The problem of fully analyzing any arbitrary bit of code to know what you and I know (that we'll never fall out of the loop) is pretty much the halting problem (if you don't know what it is, you should, google it).
In situations like this we need to work with the compiler and help it understand. I would add a return sorted; at the end of the function, change the loop condition to while (1) and replace sorted = 1; return X; with sorted = X; break; to break out of the loop and have the function return from just one place (it is much easier to read functions that have just one or very few return statements). Or just remove the sorted variable, do the returns properly and loop forever.
I think your compiler doesn't like your understanding of Control Flow. As a beginner this is one of the most cringing problems.
Your error explained: Control may reach end of non-void function. Whenever you branch your code (i.e. use loops, if, switch etc) you have to explicitly write what each branch will do. So in your code, you must return a bool by any means necessary.
I am unable to discern where the error might be, it would be great if someone can show me.
See we have two return x; statements, one in if block and second in else block. Now we think that control should return from either of these blocks conveniently. But your compiler is "concerned" about what will happen if control didn't enter either of these blocks and loop ends. Moreover, what will happen after the loop, how can control ever return to main? Hence the error.
Now what we can do to fix the problem is add a return 0; just before the end of the function. That will surely make the error disappear. However, there are better ways to solve this problem:
bool search(int value, int values[], int n) {
int min = 0, max = n;
int mid = n / 2;
bool is_found = 0;
while (min != max) {
if (value == values[mid]) {
is_found = 1;
break;
}
else if (value > values[mid]) {
min = mid + 1;
mid = (max + min) / 2;
}
else if (value < values[mid]) {
max = mid - 1;
mid = (max + min) / 2;
}
else break;
}
return is_found;
}

Search of an element on a unsorted array recursively

This is an exercise that I took from an exam. It asks to write a function that receives an unsorted array v[] and a number X and the function will return 1 if X is present in v[] or 0 if X is not present in v[]. The function must be recursive and must work in this manner:
1. Compares X with the element in the middle of v[];
2. The function calls itself (recursion!!) on upper half and on the lower half of v[];
So I've written this function:
int occ(int *p,int dim,int X){
int pivot,a,b;
pivot=(dim)/2;
if(dim==0) //end of array
return 0;
if(*(p+pivot)==X) //verify if the element in the middle is X
return 1;
a=occ(p,pivot,X); //call on lower half
b=occ(p+pivot,dim-pivot,X); //call on upper half
if(a+b>=1) //if X is found return 1 else 0
return 1;
else{
return 0;
}
}
I tried to simulated it on a sheet of paper and it seems to be correct (Even though I'm not sure) then I've written it on ideone and it can't run the program!
Here is the link: https://ideone.com/ZwwpAW
Is my code actually wrong (probably!) or is it a problem related to ideone. Can someone help me? Thank you in advance!!!
The problem is with b=occ(p+pivot,dim-pivot,X); when pivot is 0. i.e. when dim is 1.
the next function call becomes occ(p,1,X); This again leads to the call occ(p,1,X); in a continuous loop.
It can be fixed by adding a condition to the call, as shown in the code below.
int occ(int *p,int dim,int X){
int pivot,a=0,b=0;
pivot=(dim)/2;
if(dim==0){
return 0;
}
if(*(p+pivot)==X)
return 1;
if (pivot != 0)
{
a=occ(p,pivot,X);
b=occ(p+pivot,dim-pivot,X);
}
if(a+b>=1)
return 1;
else{
return 0;
}
}
The implemetation is causing a stack overflow, as the recursion does not terminate if the input contains only one element. This can be fixed as follows.
int occ(int *p, int dim, int X)
{
int pivot, a, b;
pivot = (dim) / 2;
if (dim == 0)
{
return 0;
}
if (*(p + pivot) == X)
{
return 1;
}
if (dim == 1)
{
if (*(p + pivot) == X)
{
return 1;
}
else
{
return 0;
}
}
a = occ(p, pivot, X);
b = occ(p + pivot, dim - pivot, X);
if (a + b >= 1)
{
return 1;
}
else
{
return 0;
}
}
It's enought to change only this one line in the source code to avoid the endless loop with occ(p,1,X):
//if(dim==0) //end of array
if (pivot == 0)
return 0;

Resources