Infinite recursion: binary search & asserts - c

I'm writing an implementation of binary search in C and I'm getting infinite recursion for no apparent (to me) reason. Heres my code:
/*Orchestrate program*/
int main(int argc, char* argv){
int array[] = {1,2,3,3,3,6,7,8,9,9,20,21,22};
int length = 13;
int key = 23;
binary_search(key, array, 0, length - 1);
return 0;
}
int binary_search(int key, int array[], int first_index, int last_index){
int middle;
middle = (first_index + last_index)/2;
if (first_index == last_index){
if (array[middle] == key){
printf("%d has been found at position %d\n", key, middle+1);
}
printf("item not found");
}
else if (key > array[middle]){
binary_search(key, array, middle, last_index);
}
else if (key < array[middle]){
binary_search(key, array, first_index, middle);
}
}
Based on the value of my key in main, I guess the problem lies in the first else if, but I'm not sure why. If I were to remove the first_index == last_index line, the algorithm works fine but only when the item is in the array. If the item isn't in the array, I naturally get infinite recursion.
Also, I tried to fix this problem by removing the first_index == last_index line and placing a return -1; at the end of the function, but I get the same problem that I am getting now.
EDIT:
Putting together pieces of advice I received from a few different users, I came to the following solution (fixed off by one errors and un-nested decisions):
void binary_search(int key, int array[], int first_index, int last_index){
int middle;
middle = (first_index + last_index)/2;
if (array[middle] == key){
printf("%d has been found at position %d\n", key, middle+1);
}
if (first_index == last_index){
printf("item not found");
}
else if (key > array[middle]){
binary_search(key, array, middle + 1, last_index);
}
else if (key < array[middle]){
binary_search(key, array, first_index, middle - 1);
}
}
I have a follow-up question: Could there have been a way to use asserts to assist me in finding this solution myself? (I'm just learning about asserts so I'm wondering where I can apply them)

You search ever smaller ranges of a sorted array. The bounadries of your array are inclusive.
The base case of your recursion is: If the range is empty, the key is not found. Or, in code:
if (first_index > last_index){
printf("Not found\n");
}
You should calculate and compare the middle element of your range only after you have established that the range is not empty. In that case, you have three outcomes:
The middle element is the key: bingo!
The middle element is smaller than the key: Search the right half of the array and exclude the middle element, which we have already checked.
The middle element is larger than the key: Ditto, but with the left half.
Putting this all together:
void binary_search(int key, int array[], int first_index, int last_index)
{
if (first_index > last_index){
printf("Not found\n");
} else {
int middle = (first_index + last_index) / 2;
if (array[middle] == key) printf("%d at index %d\n", key, middle);
if (key > array[middle]){
binary_search(key, array, middle + 1, last_index);
} else {
binary_search(key, array, first_index, middle - 1);
}
}
}
This function still has two things that nag me:
A function that prints the index is of little practical use. The printing should be done by the client code, i.e. by the code that calls the function. Return the found index or a special value for "not found" instead.
The range has inclusive bounds. That's not very C-like. In C, a range is usually described by an inclusive lower and an exclusive upper bound. That's how array indices and for loops work. Following this convention means that your client code doesn't have to do the awkward length - 1 calculation.
So here's a variant that returns the index or -1 if the key is not in the array:
int binary_search1(int key, int array[], int first_index, int last_index)
{
if (first_index < last_index){
int middle = (first_index + last_index) / 2;
if (array[middle] == key) return middle;
if (key > array[middle]){
return binary_search1(key, array, middle + 1, last_index);
} else {
return binary_search1(key, array, first_index, middle);
}
}
return -1;
}
and test it with:
int main()
{
int arr[6] = {3, 4, 6, 8, 12, 13};
int i;
for (i = 0; i < 20; i++) {
int ix = binary_search(i, arr, 0, 6);
if (ix < 0) {
printf("%d not found.\n", i);
} else {
printf("%d at index %d.\n", i, ix);
}
}
return 0;
}
Note that your original array has duplicate entries. This is okay, but you will get the index of any of the duplicate values, not necessarily the first one.

Your function should look like this:
void binary_search(int key, int array[], int first_index, int last_index){
int middle;
middle = (first_index + last_index)/2;
if (array[middle] == key){
printf("%d has been found at position %d\n", key, middle+1);
}
else if (first_index == last_index) {
printf("item not found");
}
else if (key > array[middle]){
binary_search(key, array, middle + 1, last_index);
}
else {
//assert (key < array[middle]); // feel free to uncomment this one and include the assert library if you want
binary_search(key, array, first_index, middle - 1);
}
}
In other words, increment or decrement middle appropriately in the recursive call.
This is important, because, for example, when you reduce to size 2 for your search and middle is your first element, then effectively you are not changing the dimension of the array in the recursive calls.
I also changed your function to void since you are not returning anything.

Related

Recursive Linear Search in C debug

Problem:1
In this code if I search a number which is not in array it should display Value not found but I don't know it's not displaying that message instead everytime it's showing Found value in element -5I don't have any clue why it's happening.
#include<stdio.h>
#define SIZE 100
size_t linearSearch(const int array[], int key, size_t size);
int main(void)
{
int a[SIZE];
size_t x;
int searchKey;
size_t element;
for(x=0; x<SIZE; ++x){
a[x] = 2*x;
}
for(x=0; x<SIZE; ++x){
if(x%10 == 0){
puts("");
}
printf("%5d", a[x]);
}
puts("\n\nEnter integer search key:");
scanf("%d", &searchKey);
// attempt to locate searchKey in array a
element = linearSearch(a, searchKey, SIZE);
// display results
if(element != -1){
printf("Found value in element %d", element);
}
else{
puts("Value not found");
}
}
size_t linearSearch(const int array[], int key, size_t size)
{
if(size<0){
return -1;
}
if(key == array[size-1]){
return size-1;
}
return linearSearch(array, key, size-1);
}
Problem:2
I can't understood how
size_t linearSearch(const int array[], int key, size_t size)
function working specially these line
if(key == array[size-1]){
return size-1;
return linearSearch(array, key, size-1);
As everyone said that you have a little mistake that is, you should write if(size==0) not if(size<0).
let me explain what's going on recursively in linearSearch() function
size_t linearSearch(const int array[], int key, size_t size)
{
if(size == 0){
return -1;
}
else
if(key == array[size-1]){
return size-1;
}
else{
return linearSearch(array, key, size-1);
}
}
Suppose you gave an input 198 as searchkey.
When you calling linearSearch() function by the statement
element = linearSearch(a, searchKey, SIZE);
you are passing reference to array[], searchKey 198, and Size 100 as argument.
In linearSearch function first if statement if(size==0) checks if the size is equal to zero if not then else if statement runs.
in else if statement If(198 == array[100-1]) condition is checked.
and we see 198 is present in array[99] so the else if condition is true thus linearSearch function return the 99 as result.
Now lets see what happend if you input 55 which is not in the array list.
if(size==0) is not true so program will skip it and will go to the next statement.
if(55 == array[100-1] will be checked as its not true then linearSearch(array, 55, 100-1) will be called. again if(55==array[99-1]) will be checked.
at some point size will become 0. and the first if(size==0) statement will execute.
1) The main problem is if(size<0){. Conditional expression will always be false. because size_t is unsigned integer. So, it returns a random position with the values found(It's undefined behavior) by chance become a large numbers(e.g. -5 is 4294967291 as unsigned) without end(not found).
if(size<0){ should be if(size==0){
2) If key match the last element, returns its position. If not, repeat with a shorter one size. key not found if size is zero.
Just change the if statement from if(size<0) to if(size==0)your code will work.

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;

Control may reach end of non-void function ...Error in implementing binary search

I am trying to implement binary search on an array. I tried to get rid of this error that I get while compiling but could not. This is the function that I made for binary search:
bool BinSearch(int key, int Array[], int min, int max)
{
if (max < min)
return false;
else
{
int mid = (min + max)/2 ;
if (key > Array[mid])
BinSearch(key, Array, mid+1, max);
else if (key < Array[mid])
BinSearch(key, Array, min, mid-1);
else
return true;
}
}
Your main mistake is you are missing a return statement for your recursive calls to BinSearch. To make this explanation easier to understand I have added some parenthesis in your code to make everything more explicit. Note the code below is the same as your code, just with some (redundant) parentheses and more appropriate indentation.
Now lets assume we have a code path where max < min is false followed by key > Array[mid] being true. Therefore we have the following program execution, annotated in the code:
bool BinSearch(int key, int Array[], int min, int max)
{
if (max < min) { // Step 1, false
return false;
}
else {
// Step 2, start the else block
int mid = (min + max)/2 ;
if (key > Array[mid]) { // Step 3, true
BinSearch(key, Array, mid+1, max); // Step 4 call BinSearch
// Step 5, finished with call to BinSearch
}
else if (key < Array[mid]) {
BinSearch(key, Array, min, mid-1);
}
else {
return true;
}
// Step 6, Done with else block
}
// Step 7, Done with function, no return statement
}
A similar thing would happen if key > Array[mid] is false and key < Array[mid] is true. This should make it clear why your compiler correctly thinks there are code paths that do not have a return. The solution, as previously pointed out in the comments is to do return BinSearch(...).

Programs works when compiled in clang, but not gcc in Windows

Have this search function that works when I compile in Linux using clang, but on Windows using MinGW gcc, I do not get the right answer. Included in the code is an array where clearly the value I'm looking for is in the array. So output should be "Found it!". Anyone know what might the issue be with windows?
#include <stdio.h>
#include <stdbool.h>
bool re_search(int value, int values[], int first, int last);
int main(void)
{
int value = 12;
int values[] = {2,4,5,12,23,34};
int n = 6;
if (re_search(value, values, 0, n-1))
{
printf("Found it!\n");
}
else
{
printf("Did not find it\n");
}
return 0;
}
bool re_search(int value, int values[], int first, int last)
{
last = last-1;
int middle = (first+last)/2;
while (first <= last)
{
if (value == values[middle])
{
return true;
}
else if (value > values[middle])
{
first = middle + 1;
middle = (first + last) / 2;
return re_search(value, &values[middle], first, last);
}
else
{
last = middle - 1;
middle = (first + last) / 2;
return re_search(value, &values[first], first, last);
}
}
return false;
}
Your recursive call return re_search(value, &values[middle], first, last); is passing in both an array which starts at the midpoint, and a new value of first which counts from the whole array's start. You want to do one or the other; not both.
That is, you first call with:
values == {2,4,5,12,23,34}
first == 0
last == 5
In the first iteration, you try middle == 2, so values[middle] is 5, which is less than 12. You then recurse with
values == {12,23,34}
first == 3
last == 5
And - oh dear! - even values[first] is now out of range. Chances are, on Linux you got (un)lucky and hit the value you were searching for past the end of the array.
does not matter whether GCC and windows.
bool re_search(int value, int values[], int first, int last){
if (first <= last){
int middle = (first+last)/2;
if (value == values[middle]){
return true;
} else if (value > values[middle]){
return re_search(value, values, middle + 1, last);
} else {
return re_search(value, values, first, middle - 1);
}
}
return false;
}
bool re_search(int value, int values[], int first, int last){
while (first <= last){
int middle = (first+last)/2;
if (value == values[middle]){
return true;
} else if (value > values[middle]){
first = middle + 1;
} else {
last = middle - 1;
}
}
return false;
}

find an element in infinite sorted array

I got this as an interview question ...
infinite array which is sorted and from some position (we dont know the position) only special symbol '$' will be there we need to find an element in that array ...
i gave a solution like get the first occurrance of $ and then do binary search on the previous part from $
to find the first occurance of $ i gave solution like increment in window size if (i,2i)
the code i gave is
#include<stdio.h>
int first(int *arr,int start,int end,int index)
{
int mid=(start+end)/2;
if((mid==start||arr[mid-1] != '$') && arr[mid]=='$')
return mid;
if(arr[mid]=='$')
return first(arr,start,mid-1,index);
else
{
if(arr[end] =='$')
return first(arr,mid+1,end,index);
else
return first(arr,end+1,(1<<index),index+1);
}
}
int binsearch(int *arr,int end ,int n)
{
int low,high,mid;
high=end-1;
low=0;
while(low<= high)
{
mid=(low+high)/2;
if(n<arr[mid])
high=mid-1;
else if (n >arr[mid])
low=mid+1;
else
return mid;
}
return -1;
}
int main()
{
int arr[20]={1,2,3,4,5,6,7,8,9,10,'$','$','$','$','$','$','$','$','$','$'};
int i =first(arr,0,2,2);
printf("first occurance of $ is %d\n",i);
int n=20;//n is required element to be found
if(i==0||arr[i-1]<n)
printf(" element %d not found",n);
else{
int p=binsearch(arr,i,n);
if(p != -1)
printf("element %d is found at index %d",n,p);
else
printf(" element %d not found",n);
}
return 0;
}
Is there any better way to do the above problem ??
And also i wanted to know to find the first occurance of $ why should we move the window only in powers of 2 why not 3 like (i,3i)
Can someone pls through some light on the recurrance relation ..pls help..
Seems like a fine way to do it to me. As a small optimization, you can stop your first routine when you reach any number bigger than the one you're searching for (not just $).
Growing the window by powers of 2 means you'll find the end in log_2(n) iterations. Growing by factors of 3 means you'll find it in log_3(n) iterations, which is smaller. But not asymptotically smaller, as O(log_2(n)) == O(log_3(n)). And your binary search is going to take log_2(n) steps anyway, so making the first part faster is not going to help your big-O running time.
The efficient part of first function in iterative format would be
private int searchNum(int[] arr, int num, int start, int end) {
int index = 0;
boolean found = false;
for (int i = 0; i < arr.length; i = 1 << index) {
if (start + i < arr.length) {
if (arr[start] <= num && arr[start + i] >= num) {
found = true;
return bsearch(arr, num, start, start + i);
} else {
start = start + i;
}
} else {
return bsearch(arr, num, start, arr.length - 1);
}
}
return 0;
}
this wont return you first occurance but instead try to find number directly as in your case you are missing probability that number itself could be found even before finding the $ symbol. So worst case complexity is O(logn)..
and best case would be (1)
after that you pass this to
private int bsearch(int[] array, int search, int first, int last) {
int middle = (first + last) / 2;
while (first <= last) {
if (array[middle] < search)
first = middle + 1;
else if (array[middle] == search) {
System.out.println(search + " found at location "
+ (middle + 1) + ".");
return middle;
} else
last = middle - 1;
middle = (first + last) / 2;
}
if (first > last)
System.out.println(search + " is not present in the list.\n");
return -1;
}
calling function
if ((pos = searchNum(arr, num, 0, 2)) != -1) {
System.out.println("found # " + pos);
} else {
System.out.println("not found");
}
This is python solution.
arr = [3,5,7,9,10,90,100,130,140,160,170,171,172,173,174,175,176]
elm = 171
k = 0
while (True):
try:
i = (1 << k) - 1 # same as 2**k - 1 # eg 0,1,3,7,15
# print k
if(arr[i] == elm):
print "found at " + str(i)
exit()
elif( arr[i] > elm):
break
except Exception as e:
break
k = k+1
begin = 2**(k-1) # go back to previous power of 2
end = 2**k -1
# Binary search
while (begin <= end):
mid = begin + (end-begin)/2
try:
if(arr[mid] == elm):
print "found at " + str(mid)
exit()
elif(arr[mid] > elm):
end = mid-1
else:
begin = mid+1
except Exception as e:
# Exception can occur if you are trying to access min element and that is not available. hence set end to mid-1
end = mid-1
print "Element not found"

Resources