binary search algorithms using iterative and recursive - c++

I am looking for an element x in a sorted array. It compares xx or the array range equals to zero I am getting segmentation fault where I went wrong I couldn't find my code is below
I am compiling in gcc complier.
#include <iostream>
using namespace std;
// iterative
int bsearch(int a[], int sz, int x)
{
int low = 0;
int high = sz -1;
while(low <= high) {
int mid = (low+high)/2;
if(x < a[mid])
high = mid - 1;
else if(x > a[mid])
low = mid + 1;
else
return a[mid];
}
return -1;
}
// recursive
int bsearch_recursive(int a[], int low, int high, int x)
{
if(low > high) return -1;
int mid = (low + high)/2;
if(x < a[mid])
bsearch_recursive(a, low, mid-1, x);
else if(x > a[mid])
bsearch_recursive(a, mid+1, high, x);
else
return a[mid];
}
void print(int n)
{
if(n == -1) {
cout << "not found" << endl;
return;
}
cout << "found" << endl;
}
int main()
{
int a[]={3, 7, 9, 16, 23, 34, 67, 87, 92};
int arraySize = sizeof(a)/sizeof(int);
int result;
result = bsearch(a, arraySize, 7);
print(result);
result = bsearch(a, arraySize, 92);
print(result);
result = bsearch(a, arraySize, 77);
print(result);
result = bsearch_recursive(a, 0, arraySize-1, 7);
print(result);
result = bsearch_recursive(a, 0, arraySize-1, 92);
print(result);
result = bsearch_recursive(a, 0, arraySize-1, 77);
print(result);
return 0;
}

Your recursive search needs to have a return value on each path, otherwise its results are undefined.
A recursive function works exactly like other functions - if it claims to be returning a value, it must do that. It doesn't just automatically return the result of the terminating recursive call.
int bsearch_recursive(int a[], int low, int high, int x)
{
if(low > high) return -1;
int mid = (low + high)/2;
if(x < a[mid])
return bsearch_recursive(a, low, mid-1, x);
else if(x > a[mid])
return bsearch_recursive(a, mid+1, high, x);
else
return a[mid];
}
Your compiler should have warned you about this - if it didn't, switch on more warnings.
If it did and you didn't care, start listening to warnings.

Below function has problem:
int bsearch_recursive(int a[], int low, int high, int x)
When you call this function recursively, you should return the value as shown below
int mid = (low + high)/2;
if(x < a[mid])
return bsearch_recursive(a, low, mid-1, x); // added return
else if(x > a[mid])
return bsearch_recursive(a, mid+1, high, x); // added return
else
return a[mid];
If you don't return from some code paths of a function that returns, the code behavious is undefined.
As side notes
if you intend to use this code for very large arrays, (low + high) may overflow, so use
int mid = low + (high - low)/2;
To make sure your compiler warns you about this compile with -Wall
option.
Returning -1 in case of error is not a good idea if array may contain both positive and negative numbers. You can return array index if found and -1 if error or device some other not found mechanism.

Related

time complexity of this algorithm written below

According to my calculations , the time complexity of this algorithm/code is O(logN) as it is an enhancement of binary search, but while submitting the code in leetcode and other platforms , it is said that the time limit is exceeded . they are also expecting the time complexity of this algorithm to be O(logN), so please confirm is the complexity of code written below is O(logN) or is it different from that?
class Solution {
public:
int findLast(vector<int> arr, int n, int x)
{
int l = 0;
int h = n - 1;
int mid;
while (h >= l) {
mid = (l + h) / 2;
if (arr[mid] == x) {
if (arr[mid + 1] != x) {
return mid;
}
else {
l = mid + 1;
}
}
else if (arr[mid] > x) {
h = mid;
}
else if (arr[mid] < x) {
l = mid + 1;
}
}
return -1;
}
int findFirst(vector<int> arr, int n, int x)
{
int l = 0;
int h = n - 1;
int mid;
while (h >= l) {
mid = (l + h) / 2;
if (arr[mid] == x) {
if (arr[mid - 1] != x) {
return mid;
}
else {
h = mid;
}
}
else if (arr[mid] > x) {
h = mid;
}
else if (arr[mid] < x) {
l = mid + 1;
}
}
return -1;
}
vector<int> searchRange(vector<int>& nums, int target)
{
int last = findLast(nums, nums.size(), target);
int first = findFirst(nums, nums.size(), target);
vector<int> v1 = { first, last };
return v1;
}
};
Your code's time complexity is O(∞) because it can perform an infinite loop.
Consider what happens when you run findLast on a one-element vector. You will have h, l, and mid equal to 0. If you enter the arr[mid] > x branch then you run h = mid; which leaves the variables unchanged, and repeats indefinitely.
Besides this, you should take the vector parameter by reference to avoid a copy which would make this a linear runtime.
Your code does not handle some corner cases where the input could be [1,1] and the target is 1. In findLast , the low and high variables would come to 1 and segmentation fault would occur when you check for arr[mid+1]. The same explanation would go for findFirst as well.
Try this and see if it helps:
int findLast(vector<int> arr, int n, int x)
{
int l = 0;
int h = n - 1;
int mid;
while (h > l)
{
mid = (l + h) / 2;
if (arr[mid] == x)
{
if (arr[mid + 1] != x)
{
return mid;
}
else
{
l = mid + 1;
}
}
else if (arr[mid] > x)
{
h = mid;
}
else if (arr[mid] < x)
{
l = mid + 1;
}
}
return arr[l] == x ? l : -1;
}

Leetcode #33 TIme Limit Exceeded

https://leetcode.com/problems/search-in-rotated-sorted-array/
The question requires that the solution be O(log n) and I believe that my solution is O(log n) since my process of finding the smallest element is O(log n) and then using binary search to find the target value is also O(log n). However, my code is exceeding the time limit.
int search(vector<int>& nums, int target) {
if(nums.size() == 0){
return -1;
}
int left = 0;
int right = nums.size() - 1;
while(left < right){
int middle = left + (right - left) / 2;
if(nums[left] < nums[middle]){
left = middle;
}
else{
right = middle;
}
}
if(target >= nums[0]){
return binarySearch(nums, target, 0, left - 1);
}
else{
return binarySearch(nums, target, left, nums.size() - 1);
}
}
int binarySearch(vector<int>& nums, int target, int start, int end){
if(nums.size() == 0 || (start == end && nums[start] != target)){
return -1;
}
int mid = start + (end - start) / 2;
if(nums[mid] == target){
return mid;
}
if(nums[mid] > target){
return binarySearch(nums, target, start, mid - 1);
}
else{
return binarySearch(nums, target, mid, end);
}
}
I believe binarySearch can run into an endless loop. When end = start + 1 you will get mid = start so if nums[start] < target you end up making a recursive call with the same parameters as before.

Recursive binary search function in C++

I'm writing a recursive binary search function for a project in C++ and for some reason, it runs infinitely and does not execute properly. My code is as follows:
int recursiveBin(const int list[], int listLength, int searchItem)
{
if(listLength == 0)
return -1;
int mid = (listLength - 1)/2;
if(list[mid] > searchItem)
return recursiveBin(list, mid - 1, searchItem);
else if(list[mid] < searchItem)
return recursiveBin(list, mid + 1, searchItem);
else
return mid;
}
Can someone please help me with this? I'm not sure what is going wrong with my function and where the infinite loop comes.
Add one more parameter to store the search boundary.
int recursiveBin(const int list[], int start, int end, int searchItem)
{
if(end > start)
return -1;
int mid = (start + end)/2;
if(list[mid] > searchItem)
return recursiveBin(list, start, mid - 1, searchItem);
else if(list[mid] < searchItem)
return recursiveBin(list, mid + 1, end, searchItem);
else
return mid;
}

Binary Search for a range

I was making binary search program to find the number of elements between the Left and Right values in a range .
I code it :
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> arr(20);
int search(int value,int low,int high)
{
if (high <= low)
return low;
int mid = (low + high) / 2;
if (arr[mid] > value)
return search(value,low,mid-1);
else
return search(value,mid+1,high);
}
int main(){
int n;
cin>>n;
//ENTER SORTED ARRAY
for(int i=0;i<n;i++){
cin>>arr[i];
}
int left;
cin>>left;
//RIGHT IS GREATER OR EQUAL TO LEFT
int right;
cin>>right;
cout<<search(right,0,n-1)-search(left,0,n-1)+1<<"\n";
}
It's giving right answer for some ranges.
But for some its giving wrong like If N=6 and array be [1 3 5 8 10 13] and say the range be [5,9] then it's giving 1 as the answer but it should be 2 as 5 and 8 both are in the range.
try this
int search(int value,int low,int high)
{
if (high <= low)
return low;
int mid = (low + high) / 2;
if(arr[mid]==value){ // add this line it would be work for you
return mid;
}
if (arr[mid] > value)
return search(value,low,mid-1);
else
return search(value,mid+1,high);
}
and make correction in main()
cout<<search(right,0,n-1)-search(left,0,n-1)<<"\n";
int search(int value,int low,int high)
{
if (high <= low + 1)
return low;
int mid = (low + high) / 2;
if (arr[mid] > value)
return search(value,low,mid);
else
return search(value,mid,high);
}
And in your main function
cout<<search(right+1,0,n-1)-search(left,0,n-1)<<"\n";
One problem is that when arr[mid] == value, you just ignore it and recurse to the right.
You'll need to either include mid in your right range, or return mid if arr[mid] == value.
I also see duplicate values (if these are possible) being a problem - when recursing to find the left-most position, you need to find the first duplicate value, when recursing to find the right-most position, you need to find the last duplicate value, so a single function without a flag to indicate which one we're doing isn't going to work. To illustrate the problem:
If the range is [5,5] and the input is [1,2,5,5,5,6,8], the same recursive call finding the position of 5 will always return the position of the same 5, where-as you need to return index 2 for the left range and index 4 for the right, as to get 3 as your output.
There is no check that arr[mid] can be == value. In your example, first iteration for left == 5 gives mid == ( 0 + (6-1) )/2 = 5/2 = 2 and arr[2] is exactly 5. We should stop, but your code goes to the branch search(5, 3, 5);
The logic of your program seems wrong, if you want to find the number of elements in the arr that are in the range of [left,right], try this:
int i;
int count = 0;
for(i = 0; i < n; i++) {
if (arr[i] >= left && arr[i] <= right)
count++;
}
If you insist on using binary search try this :
static int search(int value,int low,int high)
{
if (high <= low)
return low;
int mid = (low + high) / 2;
if (arr[mid] == value)
return mid;
int idx;
if (arr[mid] > value)
idx = search(value,low,mid-1);
else
idx = search(value,mid+1,high);
if (value == arr[idx]) {
return idx;
}
else {
if(value > arr[idx])
return mid +1;
else
return mid;
}
}

BinarySearch returning index of where it belongs

So i am looking to write a code to return the index that the key is or if it is not there, where it should be. what am i missing ?
min is 0, max is size - 1, buf is sorted
int binarySearch(string buf[], string key, int min, int max){
int mid;
while (max >= min){
mid = (min + max) / 2;
if (buf[mid] < key)
min = mid + 1;
else if (buf[mid] > key)
max = mid - 1;
else
return mid;
}
return min;
}
I had practically the same problem, so I wrote this generic code (maybe you may want to use a different namespace than std ;) ) The code below returns the an iterator to the largest element in the sequence which is smaller than or equal to val. It uses O(N log N) time for N = std::difference(first, last), assuming O(1) random access on [first ... last).
#include <iostream>
#include <vector>
#include <algorithm>
namespace std {
template<class RandomIt, class T>
RandomIt binary_locate(RandomIt first, RandomIt last, const T& val) {
if(val == *first) return first;
auto d = std::distance(first, last);
if(d==1) return first;
auto center = (first + (d/2));
if(val < *center) return binary_locate(first, center, val);
return binary_locate(center, last, val);
}
}
int main() {
std::vector<double> values = {0, 0.5, 1, 5, 7.5, 10, 12.5};
std::vector<double> tests = {0, 0.4, 0.5, 3, 7.5, 11.5, 12.5, 13};
for(double d : tests) {
auto it = std::binary_locate(values.begin(), values.end(), d);
std::cout << "found " << d << " right after index " << std::distance(values.begin(), it) << " which has value " << *it << std::endl;
}
return 0;
}
Source: http://ideone.com/X9RsFx
The code is quite generic, it accepts std::vectors, std::arrays and arrays, or any sequence that allows random access. The assumption (read precondition) is that val >= *first and that the values [first, last) are sorted, like needed for std::binary_search.
Feel free to mention bugs or malpractices that I have used.
int binary_srch_ret_index(ll inp[MAXSIZE], ll e, int low, int high) {
if (low > high) {
return -1;
}
int mid = (low + high) / 2;
if (e == inp[mid]) {
return mid;
}
if (e < inp[mid]) {
return binary_srch(inp, e, low, mid - 1);
} else {
return binary_srch(inp, e, mid + 1, high);
}
}
You searched for a character and you assumed that charaters in the buf are sorted.
If you want to search for a string use a string match pattern algorithm.
(http://en.wikipedia.org/wiki/String_searching_algorithm)
If you want to search a character or a number in an ordered array then see this:
http://www.programmingsimplified.com/c/source-code/c-program-binary-search
In binary search you can do value type search not reference type. If you want to search for string in string array you have to write a complex program or use has table
This seems to work:
#include <iostream>
#include <cassert>
int binarySearch(int buf[], int key, int min, int max);
int main()
{
int data[] = {1,2,4,6,7,9};
for(int i=0; i<6; i++)
{
int result = binarySearch(data, data[i], 0, 5);
assert(result == i);
}
assert(binarySearch(data, 3, 0, 5) == 1);
assert(binarySearch(data, 5, 0, 5) == 2);
assert(binarySearch(data, 8, 0, 5) == 4);
assert(binarySearch(data, 10, 0, 5) == 5);
return 0;
}
int binarySearch(int buf[], int key, int min, int max)
{
int mid;
while (max >= min){
mid = (min + max) / 2;
if (buf[mid] < key)
min = mid + 1;
else if (buf[mid] > key)
max = mid - 1;
else
return mid;
}
return std::min(min, max);
}