So I'm trying to write a binary search function that uses recursion and keep getting a segmentation fault if I go past two values in the array. I've looked at a bunch of other code doing what I'm trying to do and as far as I can see they appear to do the same thing. I'm a very novice programmer and feel like I'm banging my head against the wall with this. Any help would be appreciated.
int search(int value, int array[], int start, int end)
{
//Define new variables for use in recursion
int sizeArray, middleOfArray;
//Get size of array
sizeArray = (end - start) + 1;
//Find midpoint of array based off size
middleOfArray = sizeArray / 2;
//Base Case 1, if array unscannable, return -1
if (start > end) {
return -1;
}
//Recursive Cases
else
{
//If midpoint in array is > target value,
//Search from beginning of array->one below midpoint
if (array[middleOfArray] > value){
return search(value, array, start, middleOfArray - 1);
}
//If midpoint in array is < target value,
//search from one above midpoint->end of array
else if (array[middleOfArray] < value) {
return search(value, array, middleOfArray + 1, end);
}
//If none of the other cases are satisfied, value=midpoint
//Return midpoint
else {
return middleOfArray;
}
}
}
The problem is here:
middleOfArray = sizeArray / 2;
It should be like this:
middleOfArray = start + sizeArray / 2;
You can also get middle of array like this. Which will save you from one extra variable sizeofArray.
middleofArray=(start+end)/2;
Related
I need your help please.
I need to do a recursive function that finds the minimum and the maximum of any array it receives.
I need to implement function void minMax(int arr[], int left, int right, int min_max[]), but I don't know how to start, I would like if you'll give me some ideas.
This is an e.x to how the output supposed to show:
min_max[1]=100 ו min_max[0]=(-4)
On this detail:
left = 2 , right = 5, arr = [3,−1,3,100,2,−4,3], assumption : left <= right.
Thank you all.
i think what you are looking for is the Tournament Method :
Divide the array into two parts and compare the maximums and minimums of the two parts to get the maximum and the minimum of the whole array
(this is similar to binary search)
#include<stdio.h>
struct pair
{
int min;
int max;
};
struct pair getMinMax(int arr[], int low, int high)
{
struct pair minmax, mml, mmr;
int mid;
// If there is only one element
if (low == high)
{
minmax.max = arr[low];
minmax.min = arr[low];
return minmax;
}
/* If there are two elements */
if (high == low + 1)
{
if (arr[low] > arr[high])
{
minmax.max = arr[low];
minmax.min = arr[high];
}
else
{
minmax.max = arr[high];
minmax.min = arr[low];
}
return minmax;
}
/* If there are more than 2 elements */
mid = (low + high)/2;
mml = getMinMax(arr, low, mid);
mmr = getMinMax(arr, mid+1, high);
/* compare minimums of two parts*/
if (mml.min < mmr.min)
minmax.min = mml.min;
else
minmax.min = mmr.min;
/* compare maximums of two parts*/
if (mml.max > mmr.max)
minmax.max = mml.max;
else
minmax.max = mmr.max;
return minmax;
}
/* Driver program to test above function */
int main()
{
int arr[] = {1000, 11, 445, 1, 330, 3000};
int arr_size = 6;
struct pair minmax = getMinMax(arr, 0, arr_size-1);
printf("nMinimum element is %d", minmax.min);
printf("nMaximum element is %d", minmax.max);
getchar();
}
source : https://www.geeksforgeeks.org/maximum-and-minimum-in-an-array/ (Method 2)
First of all this question has a terrible redaction. In order to get better answers you should work more on your questions otherwise it makes it harder for the other people to help you and also feels like you haven't done enough prior research.
About the content of your question I would solve this with pseudocode first (As with any other "hard" problem). I supose this is homework because you already have the function signature.
The left and right parameters aren't needed or I am not understanding what they are used for.
The pseudocode function could look like this:
function minMax(arr, mixMax)
if arr is empty
return
elem = extract last elem from arr
if mixMax[0] is empty or elem > mixMax[0]
mixMax[0] = elem
if mixMax[1] is empty or elem < mixMax[1]
mixMax[1] = elem
minMax(arr, minMax)
So I have an integer array called OriginalArray that contains a bunch of integers. I want to be able to make it so that the user can input any value and if it's in the array, provide the location of that value and if it appears multiple times in the array, have it provide all the locations and otherwise have it provide an error message.
I WANT to use the technique of binary search and/or linear search and/or interpolation search to be able to achieve this, recursive or iteratively I don't mind.
Sorry about the little information to go off trying to tackle a hard task for me and I'm not the most experienced :)
static object BinarySearchRecursive(int[] inputArray, int key, int min, int max)
{
if (min > max)
{
return "Nil";
}
else
{
int mid = (min + max) / 2;
if (key == inputArray[mid])
{
return ++mid;
}
else if (key < inputArray[mid])
{
return BinarySearchRecursive(inputArray, key, min, mid - 1);
}
else
{
return BinarySearchRecursive(inputArray, key, mid + 1, max);
}
}
}
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;
}
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;
}
Assuming you don't know the number of elements you are searching and given an API that accepts an index and will return null if you are outside the bounds (as implemented here with the getWordFromDictionary method), how can you perform a binary search and implement the isWordInDictionary() method for client programs?
This solution works, but I ended up doing a serial search above the level where I found an initial high-index value. The search through the lower range of values was inspired by this answer. I also peeked at BinarySearch in Reflector (C# decompiler), but that has a known list length, so still looking to fill in the gaps.
private static string[] dictionary;
static void Main(string[] args)
{
dictionary = System.IO.File.ReadAllLines(#"C:\tmp\dictionary.txt");
Console.WriteLine(isWordInDictionary("aardvark", 0));
Console.WriteLine(isWordInDictionary("bee", 0));
Console.WriteLine(isWordInDictionary("zebra", 0));
Console.WriteLine(isWordInDictionaryBinary("aardvark"));
Console.WriteLine(isWordInDictionaryBinary("bee"));
Console.WriteLine(isWordInDictionaryBinary("zebra"));
Console.ReadLine();
}
static bool isWordInDictionaryBinary(string word)
{
// assume the size of the dictionary is unknown
// quick check for empty dictionary
string w = getWordFromDictionary(0);
if (w == null)
return false;
// assume that the length is very big.
int low = 0;
int hi = int.MaxValue;
while (low <= hi)
{
int mid = (low + ((hi - low) >> 1));
w = getWordFromDictionary(mid);
// If the middle element m you select at each step is outside
// the array bounds (you need a way to tell this), then limit
// the search to those elements with indexes small than m.
if (w == null)
{
hi = mid;
continue;
}
int compare = String.Compare(w, word);
if (compare == 0)
return true;
if (compare < 0)
low = mid + 1;
else
hi = mid - 1;
}
// punting on the search above the current value of hi
// to the (still unknown) upper limit
return isWordInDictionary(word, hi);
}
// serial search, works good for small number of items
static bool isWordInDictionary(string word, int startIndex)
{
// assume the size of the dictionary is unknown
int i = startIndex;
while (getWordFromDictionary(i) != null)
{
if (getWordFromDictionary(i).Equals(word, StringComparison.OrdinalIgnoreCase))
return true;
i++;
}
return false;
}
private static string getWordFromDictionary(int index)
{
try
{
return dictionary[index];
}
catch (IndexOutOfRangeException)
{
return null;
}
}
Final Code after answers
static bool isWordInDictionaryBinary(string word)
{
// assume the size of the dictionary is unknown
// quick check for empty dictionary
string w = getWordFromDictionary(0);
if (w == null)
return false;
// assume that the number of elements is very big
int low = 0;
int hi = int.MaxValue;
while (low <= hi)
{
int mid = (low + ((hi - low) >> 1));
w = getWordFromDictionary(mid);
// treat null the same as finding a string that comes
// after the string you are looking for
if (w == null)
{
hi = mid - 1;
continue;
}
int compare = String.Compare(w, word);
if (compare == 0)
return true;
if (compare < 0)
low = mid + 1;
else
hi = mid - 1;
}
return false;
}
You can implement a binary search in two phases. In the first phase, you grow the size of the interval you're searching in. Once you detect you're outside the bounds, you can do a normal binary search in the latest interval you found. Something like this:
bool isPresentPhase1(string word)
{
int l = 0, d = 1;
while( true ) // you should eventually reach an index out of bounds
{
w = getWord(l + d);
if( w == null )
return isPresentPhase2(word, l, l + d - 1);
int c = String.Compare(w, word);
if( c == 0 )
return true;
else if( c < 0 )
isPresentPhase2(value, l, l + d - 1);
else
{
l = d + 1;
d *= 2;
}
}
}
bool isPresentPhase2(string word, int lo, int hi)
{
// normal binary search in the interval [lo, hi]
}
Sure you can. Start at index one, and double your query index until you hit something that's lexographically larger than your query word(Edit: or null). Then you can narrow down your search space again until you find the index, or return false.
Edit: Note that this does NOT add to your asymptotic runtime, and it is still O(logN), where N is the number of items in the series.
So, I'm not sure I entirely understand the problem from your description, but I'm assuming you're trying to search through a sorted array of unknown length to find a particular string. I'm also assuming that there are no nulls in the actual array; the array only returns null if you ask for an index that's out of bounds.
If those things are true, the solution should be just a standard binary search, albeit one where you search over the entire integer space, and you just treat null the same as finding a string that comes after the string you are looking for. Essentially just imagine that your sorted array of N strings is really a sorted array of INT_MAX strings sorted with nulls at the end.
What I don't quite understand is that you seem to basically have done that already (at least from a cursory look at the code), so I think I might not understand your problem completely.