I'm 99% sure my problem is that I'm setting low to zero every start. But I'm not sure how to keep low consistently representative of the low index regardless of the depth of my recursion. If it accurately told me the index of the low index I don't think I would have a problem.
Here's my code so far:
int recBSearch(vector<int> v, int size, int item)
{
int index = size / 2;
int curr = v[index];
int low = 0;
int high = size -1;
if (v[index] == item)
return index;
else if (v[index] > item)
{
high = index;
index = (high+low)/2;
size = high - low;
return recBSearch(v, size, item);
}
else if (v[index] < item)
{
low = index;
index = (high+low)/2;
size = high - low;
return recBSearch(v, size, item);
}
return -1;
}
This won't work when you are trying to search in the upper half of the vector, because what you really need to create is a slice of the vector.
There is already a binary search but if you are determined to write your own, use an iterator-range in the parameters. (You can either pass in two plain iterators or a boost range).
You want -1 if not found else the iterator location, so in your slice (iterator range) you would need to specify a starting index number in case it is found.
You could also pass, as an alternative, the vector (by const reference) and the range in which you wish to search.
Your last line is unreachable. Instead it should be the terminating condition of your recursion before you do any evaluation. (If your range is empty)
The version that would iterate by passing by reference and using index numbers (simplest) would look like this:
int recBSearch( std::vector<int> const& vec, int start, int end, int value )
{
if( start == end )
{
return -1;
}
int index = (start + end) / 2;
// continue from here
}
end would indicate "one past the last element" so if the vector has size 5, the first iteration would pass 0 and 5. If the vector is empty, you pass 0 and 0.
As an exercise, "can it be done with 3 parameters"?
Yes...
typedef std::vector<int>::const_iterator citer;
int recBSearch( citer start, citer end, int value )
{
if( start == end )
{
return -1;
}
citer middle = start + (end-start)/2;
if( *value == *middle )
{
return middle - start;
}
else if ( *value < *middle )
{
return recBSearch( start, middle, value );
}
else // note the change here
{
int res = recBSearch( middle+1, end, value );
if( res == -1 )
return -1;
else
return res + 1 + (middle-start);
}
}
If you want to do it recursive, your method needs to take the search range as parameters. Else you can't keep track of where to search in the rucursive call assuming you always give the full vector to the function.
So your method signature should be like:
int recBSearch(vector<int> v, int first, int last, int item)
Binary search basically works by dividing your range in 2 halves and searching in each one of them. Your code shows that you operate on the lower half for your both branches. You need to pass to the recursive call the higher half of your v vector in the second else if as well as size/2 instead of size.
Related
i have to find the index of an integer in an array using a recursive function this is what i have up to now:
#include <iostream>
int linear_search(int array[], int choice_, int size) {
if (array[choice_] >= 0) {
return array[choice_];
}
else {
return -1;
}
}
for example if the:
int array[]= {3,4,7,8};
if i type that i want to search for number 3 it should give me the index of 0 but instead it gives me the number 8. can i get some advise please?
Recursion is about narrowing down a problem to a smaller problem.
In the case of this particular search, try to think of it in terms of the found-item being either in the first position in the array, or maybe in the remainder of the array. This then reduces the problem to searching a smaller array, until you either find the item or you hit the trivial case of an empty array.
int linear_search(int array[], int choice_, int size)
{
// Array is empty -- not found
if (size <= 0)
return -1;
// Found at position 0
if (array[0] == choice_)
return 0;
// TODO: Search position in remaining array
int pos = linear_search(/* USE BRAIN HERE */);
// TODO: You may want to do something to the result before returning it
return pos;
}
As you can see, I've left some parts for you to fill in. I have faith in you. You can do it!
Happy coding!
This is binary search. It is a recursive function.
int binary_search_recursive(const int b[], int search_key, int low, int high)
{
if (low > high)
return -1;
int mid = low + (high - low) / 2;
if (search_key == b[mid])
return mid;
else if (search_key < b[mid])
return binary_search_recursive(b, search_key, low, mid - 1);
else
return binary_search_recursive(b, search_key, mid + 1, high);
}
This code is wrong
if (array[choice_] >= 0) {
return array[choice_];
When you do array[choice_] you are looking at the array value at index choice_. That is not what you want. Instead you want to find out if the array at some index is equal to choice_. That would be if (array[some_index] == choice_) return some_index;
Further, to make this a recursive approach, the function needs to call itself. Your code doesn't do that so it's not recursive.
Here is a recursive approach:
int searchArray(const int* array, const int choice_, const int size)
{
if (size > 0)
{
if (array[size-1] == choice_) return size-1; // Hit! Return the index
return searchArray(array, choice_, size-1); // Recursive call - pretend array is 1 shorter
}
return -1;
}
The code looks at the last element in the array.
If it is a hit it simply returns the index.
If it is not a hit, it calls itself but decrements size to pretend that the array is one element shorter.
In this way it goes from the end of the array towards the start of the array while looking for choice_.
BTW: Notice that it's a very bad idea to use recursion for this task - never do that! Use a simple for loop. But I guess this is just another example of a very bad homework task...
I'm trying to write a function that can do a binary search for any given STL container (i.e lists, vectors, etc). My approach was using two iterators, one for the beginning and end of the sequences.
template <class ln, class T> int binarysearch_list(ln first, ln last, T search_value) {
int low = 0;
int high = 0;
int midpoint = 0;
int start = 0;
while(first != last) {
first++;
start++;
}
high = start;
while(low <= high) {
ln current = next(first, midpoint);
if(search_value == *current) { // if we already find search_value at the midpoint we can simply exit
return midpoint;
} else if(search_value > midpoint) {
low = midpoint + 1; // change the low to the next element after midpoint
} else if(search_value < midpoint) {
high = midpoint - 1;
}
}
return -1;
}
The first while loop is used to get the size, the second one is the actual binary search. I get an error at ln current = next(first, midpoint), I'm not sure how to tackle increment the iterator. Ideally, where you see "if(search_value == *current)" it will act like vector[midpoint] or list(midpoint). I need a way to read the nth element of any given sequence using a begin and end iterator, and I need a way to flexibly increment an iterator by n. I've tried advance(first, amount), (first+amount), and many others but I'm stumped!
I'm trying to write a function which takes an array of integers & searches the part of the array between the first and last for the given value. If the value is in the array, return that position. If it is not, I want to return -1.
Here is the code for my function.
int binarySearch(int *array, int min, int max, int value) {
int guess = 0;
bool found = false;
while (!found) {
guess = ((array[min] + array[max]) / 2);
if (array[guess] == value) {
found = true;
return guess;
}
else if (array[guess] < value) {
min = guess + 1;
}
else if (array[guess] > value) {
max = guess - 1;
}
}
return -1;
}
I'm unsure how to break out of the while loop when the value you are searching for is not in the array? This is the pseudocode I am following for implementing a binary search function :
Let min = 0 and max = n-1(array size -1 ). Compute guess as the average of max and
min, rounded down (so that it is an integer).
If array[guess] equals
target, then stop. You found it! Return guess.
If the guess was too
low, that is, array[guess] < target, then set min = guess + 1.
Otherwise, the guess was too high. Set max = guess - 1.
Go back to step 2.
I think it makes sense to change what the function returns. Instead of returning guess, it should return a valid index if the item is found and -1 otherwise.
Also, you are using guess as a value and as an index. That will definitely cause problems.
guess is a value below.
guess = ((array[min] + array[max]) / 2);
guess is an index below.
else if (array[guess] < value) {
Here's my suggestion:
// Return the index if found, -1 otherwise.
int binarySearch(int *array, int first, int last, int value)
{
// Terminating condition 1.
// If first crosses last, the item was not found.
// Return -1.
if ( first > last )
{
return -1;
}
int mid = (first + last)*0.5;
// Terminating condition 2.
// The item was found. Return the index.
if ( array[mid] == value )
{
return mid;
}
// Recurse
if (array[mid] < value)
{
return binarySearch(array, mid+1, last, value);
}
else
{
return binarySearch(array, first, mid-1, value);
}
}
No need for recursion if you use a while loop, just remember to calculate guess every time, and set guess to the middle of the indexes, not their values:
int binarySearch (int *array, int first, int last, int value)
{
int guess = 0;
while (first != last || array[guess] == value) {
guess = (first + last) / 2;
if (array[guess] == value)
return guess;
else if (array[guess] < value)
last = guess + 1;
else if (array[guess] > value)
first = guess - 1;
}
return -1;
}
I would also suggest
int first = 0, last = sizeof(array) / sizeof(array[0]) - 1;
instead of passing them as arguments.
I have to find the first instance of the sub string "xy" in a char array, by using divide and conquer to split my array into half (so array[0...mid] and array[mid+1...size] where mid = size+1/2) and recursively running my algorithm on both halves. The substring 'xy' could be in the left half, it could be in the right half, or it could be between the two halves. It returns the index of 'x' if the first 'xy' is found, otherwise returns a -1. My method is allowed two parameters, the (pointer to) array and the size of the array. I tried to do it by using a modified binary search, and the code is as follows:
(PS. this is pseudocode that resembles C++, doesn't have to be proper just the logic has to be good)
public int xy-search(char* data, int n){ //starts at l=0 and r == n-1
int l = 0; //left index
int r = n-1; // right index
if (n==1)
return -1;
if (l>r) // not found
return -1;
int mid = l+r/2; //get mid point
if (data[mid] == ‘x’ && data[mid+1] == ‘y’)
return mid;
else if (l==r) // not found
return -1;
else {
int left = xy-search(data, left); //check left
int right = xy-search(data+left+1, n - left - 1); // check right
if (left != -1) //if found at left, return index
return left;
if (right != -1) //if found at right, return index
return right;
else
return -1;
}
}
I need someone to check my work and tell me if I am going about it wrong. Also, I feel like there should be a condition that checks the left first and if that fails, then the right, as we are looking for the first instance of 'xy'.
i don't know why you want to use divide and concur.
any way. your data might be large and you want to use multi thread and so on....
i think you can use something like this:
int xy_Find(string str , int start , int end)
{
int min = (start + end) / 2;
if (str.substr(start,2) == "xy")
{
return start;
}
if (end - start <= 2)
{
return -1 ;
}
else
{
int leftPos = xy_Find(str , start , min + 1);
if (leftPos != -1)
{
return leftPos;
}
int rightPos = xy_Find(str , min , end);
if (rightPos != -1)
{
return rightPos;
}
}
return -1;
}
there is one thing, i divided it into tow parts. but they have one common character so if "xy" is at mid it wont work wrong.
A binary search is used when the data is sorted or if you can be sure if one half of the array doesn't contain the data you're searching, so, in your case the efficiency of your algorithm will be worse than a naive linear search.
Even then if binary search is the way you want to go, your code has some problems. For binary search you need to pass two indexes. The starting point and the ending point,so that data is divided properly.
int xysearch(char *data, int start,int end){
int l=start;
int r=end;
if(l>=r){
return -1;
}
int mid=(l+r)/2;
int left=xysearch(data,l,mid);
if(left!=-1){
return left;
}
if(mid+1<strlen(data)&&data[mid]=='x'&&data[mid+1]=='y'){
return mid;
}
int right=xysearch(data,mid+1,r);
if(right!=-1){
return right;
}
return -1;
}
edit: Now the program checks left first then the right
So, I was trying to implement the binary search algorithm (as generic as possible which can adapt to different cases). I searched for this on the internet, and some use, while (low != high) and some use, while (low <= high) and some other different condition which is very confusing.
Hence, I started writing the code for finding the first element which is greater than a given element. I wish to know if there is a more elegant solution than this?
Main code:
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <utility>
#include <algorithm>
#include <stack>
#include <queue>
#include <climits>
#include <set>
#include <cstring>
using namespace std;
int arr1[2000];
int n;
int main (void)
{
int val1,val2;
cin>>n;
for (int i = 0; i < n; i++)
cin>>arr1[i];
sort(arr1,arr1+n);
cout<<"Enter the value for which next greater element than this value is to be found";
cin>>val1;
cout<<"Enter the value for which the first element smaller than this value is to be found";
cin>>val2;
int ans1 = binarysearch1(val1);
int ans2 = binarysearch2(val2);
cout<<ans1<<"\n"<<ans2<<"\n";
return 0;
}
int binarysearch1(int val)
{
while (start <= end)
{
int mid = start + (end-start)/2;
if (arr[mid] <= val && arr[mid+1] > val)
return mid+1;
else if (arr[mid] > val)
end = mid-1;
else
start = mid+1;
}
}
Similarly, for finding the first element which is smaller than the given element,
int binarysearch2(int val)
{
while (start <= end)
{
int mid = start + (end-start)/2;
if (arr[mid] >= val && arr[mid] < val)
return mid+1;
else if (arr[mid] > val)
end = mid-1;
else
start = mid+1;
}
}
I often get super confused when I have to modify binary search for such abstraction. Please let me know if there is simpler method for the same? Thanks!
As you say, there are different ways to express the end condition for binary search and it completely depends on what your two limits mean. Let me explain mine, which I think it's quite simple to understand and it lets you modify it for other cases without thinking too much.
Let me call the two limits first and last. We want to find the first element greater than a certain x. The following invariant will hold all the time:
Every element past last is greater than x and every element before
first is smaller or equal (the opposite case).
Notice that the invariant doesn't say anything about the interval [first, last]. The only valid initialization of the limits without further knowledge of the vector is first = 0 and last = last position of the vector. This satisfies the condition as there's nothing after last and nothing before first, so everything is right.
As the interval [first, last] is unknown, we will have to proceed until it's empty, updating the limits in consequence.
int get_first_greater(const std::vector<int>& v, int x)
{
int first = 0, last = int(v.size()) - 1;
while (first <= last)
{
int mid = (first + last) / 2;
if (v[mid] > x)
last = mid - 1;
else
first = mid + 1;
}
return last + 1 == v.size() ? -1 : last + 1;
}
As you can see, we only need two cases, so the code is very simple. At every check, we update the limits to always keep our invariant true.
When the loop ends, using the invariant we know that last + 1 is greater than x if it exists, so we only have to check if we're still inside our vector or not.
With this in mind, you can modify the binary search as you want. Let's change it to find the last smaller than x. We change the invariant:
Every element before first is smaller than x and every element
after last is greater or equal than x.
With that, modifying the code is really easy:
int get_last_smaller(const std::vector<int>& v, int x)
{
int first = 0, last = int(v.size()) - 1;
while (first <= last)
{
int mid = (first + last) / 2;
if (v[mid] >= x)
last = mid - 1;
else
first = mid + 1;
}
return first - 1 < 0 ? -1 : first - 1;
}
Check that we only changed the operator (>= instead of >) and the return, using the same argument than before.
It is hard to write correct programs. And once a program has been verified to be correct, it should have to be modified rarely and reused more. In that line, given that you are using C++ and not C I would advise you to use the std C++ libraries to the fullest extent possible. Both features that you are looking for is given to you within algorithm.
http://en.cppreference.com/w/cpp/algorithm/lower_bound
http://en.cppreference.com/w/cpp/algorithm/upper_bound
does the magic for you, and given the awesome power of templates you should be able to use these methods by just adding other methods that would implement the ordering.
HTH.
To answer the question in part, it would be possible to factor out the actual comparison (using a callback function or similar), depending on whether the first element which is larger than the element is to be searched or the first element which is smaller. However, in the first code block, you use
arr[mid] <= val && arr[mid+1] > val
while in the second block, the index shift in the second condition
if (arr[mid] >= val && arr[mid] < val)
is omitted, which seems to be inconsistent.
Your search routines had some bugs [one was outright broken]. I've cleaned them up a bit, but I started from your code. Note: no guarantees--it's late here, but this should give you a starting point. Note the "lo/hi" is standard nomenclature (e.g. lo is your start and hi is your end). Also, note that hi/lo get set to mid and not mid+1 or mid-1
There are edge cases to contend with. The while loop has to be "<" or "mid+1" will run past the end of the array.
int
binarysearch_larger(const int *arr,int cnt,int val)
// arr -- array to search
// cnt -- number of elements in array
// val -- desired value to be searched for
{
int mid;
int lo;
int hi;
int match;
lo = 0;
hi = cnt - 1;
match = -1;
while (lo < hi) {
mid = (hi + lo) / 2;
if (arr[mid] <= val) && (arr[mid+1] > val)) {
if ((mid + 1) < cnt)
match = mid + 1;
break;
}
if (arr[mid] > val)
hi = mid;
else
lo = mid;
}
return match;
}
int
binarysearch_smaller(const int *arr,int cnt,int val)
// arr -- array to search
// cnt -- number of elements in array
// val -- desired value to be searched for
{
int mid;
int lo;
int hi;
int match;
lo = 0;
hi = cnt - 1;
match = -1;
while (lo < hi) {
mid = (hi + lo) / 2;
if (arr[mid] <= val) && (arr[mid+1] > val)) {
match = mid;
break;
}
if (arr[mid] > val)
hi = mid;
else
lo = mid;
}
// the condition here could be "<=" or "<" as you prefer
if ((match < 0) && (arr[cnt - 1] <= val))
match = cnt - 1;
return match;
}
Below is a generic algorithm that given a sorted range of elements and a value, it returns a pair of iterators, where the value of the first iterator is the first element in the sorted range that compares smaller than the entered value, and the value of the second iterator is the first element in that range that compares greater than the entered value.
If the pair of the returned iterators points to the end of the range it means that entered range was empty.
I've made it as generic as I could and it also handles marginal cases and duplicates.
template<typename BidirectionalIterator>
std::pair<BidirectionalIterator, BidirectionalIterator>
lowhigh(BidirectionalIterator first, BidirectionalIterator last,
typename std::iterator_traits<BidirectionalIterator>::value_type const &val) {
if(first != last) {
auto low = std::lower_bound(first, last, val);
if(low == last) {
--last;
return std::make_pair(last, last);
} else if(low == first) {
if(first != last - 1) {
return std::make_pair(first, std::upper_bound(low, last - 1, val) + 1);
} else {
return std::make_pair(first, first);
}
} else {
auto up = std::upper_bound(low, last, val);
return (up == last)? std::make_pair(low - 1, up - 1) : std::make_pair(low - 1, up);
}
}
return std::make_pair(last, last);
}
LIVE DEMO