Given an integer and a sorted array of integers, write a binary search function named binary_search that prints the number of comparisons performed doing a binary search. The function should take 3 arguments:
the number searched for,
the array of integers, and
the number of elements in the array.
If the number searched for is not in the array then the function should return the maximum number of searches to determine the element is not in the array.
Here is an example call to the function:
#include <iostream>
using namespace std;
//Function for binary_search
int binary_search(int search_value, int lst[], int elements)
{
//Dividing the array elements to its half
int mid = elements / 2;
//Condition to check search value is less then list of mid element and return it.
if (lst[mid] > search_value)
return binary_search( elements,lst, mid);
//Condition to check search value is greater then list of mid element and return it.
else if (lst[mid] < search_value)
return binary_search( search_value,&lst[mid], (elements + 1)/2);
else
return mid;
}
int main()
{
int lst[] = {0, 1, 2, 18, 19, 20, 25};
std:cout << binary_search(20, lst, 7);
}
When I search for 20 it returns the index it is found, which is 5, instead of the number of comparisons, which should be 2.
There are a few problems with your code. First off this line:
return binary_search( elements,lst, mid);
Since your first argument is the number you are searching for, it should always be the same, search_value.
Then, the idea behind a binary search is that the number of elements is halved with each call, so you don't need to change your third argument at any point, it always is elements/2 + 1.
Finally, as mentioned in the comments, your function doesn't return the number of comparisons but rather the number "mid". Since each call does a single comparison, you essentially have to find the number of calls. So, your base case for recursion (when you find the number you are searching for) should return 1, since to find it you have done a comparison. Then you just return 1 + the number of recursive calls already made.
In the end the code should look like this,
int binary_search(int search_value, int lst[], int elements)
{
int mid = elements / 2;
if (lst[mid] > search_value)
return 1 + binary_search( search_value, lst, elements/2 + 1);
else if (lst[mid] < search_value)
return 1 + binary_search( search_value, &lst[mid], elements/2 + 1);
else
return 1;
}
I would propose the solution below:
[Demo]
#include <iostream> // cout
//Function for binary_search
int binary_search(int search_value, int lst[], int elements)
{
//Base case: not found
if (elements == 0) { return 1; }
//Dividing the array elements to its half
int mid = elements / 2;
//Condition to check search value is less then list of mid element and return it.
if (lst[mid] > search_value)
{
return 2 + binary_search(search_value, lst, mid);
}
//Condition to check search value is greater then list of mid element and return it.
else if (lst[mid] < search_value)
{
return 3 + binary_search(search_value, &lst[mid + 1], elements - mid - 1);
}
else
{
return 3;
}
}
int main()
{
int lst[] = {0, 1, 2, 18, 19, 20, 25};
std::cout << "lst: ";
for (auto&& i : lst)
{
std::cout << i << " ";
}
std::cout << "\n";
for (auto&& i : lst)
{
std::cout << "binary_search(" << i << ", lst, 7): "
<< binary_search(i, lst, 7) << "\n";
}
std::cout << "binary_search(10, lst, 7): "
<< binary_search(10, lst, 7) << "\n";
}
// Outputs:
//
// lst: 0 1 2 18 19 20 25
// binary_search(0, lst, 7): 7
// binary_search(1, lst, 7): 5
// binary_search(2, lst, 7): 8
// binary_search(18, lst, 7): 3
// binary_search(19, lst, 7): 8
// binary_search(20, lst, 7): 6
// binary_search(25, lst, 7): 9
// binary_search(10, lst, 7): 9
Explanation:
We add a base case for calls to binary_search with 0 elements. This is a safety case for calls with 0 elements, but also a base case during recursive calls when an element is not found. Since we are doing a comparison, we return 1.
if (elements == 0) { return 1; }
For values smaller than the pivot element, lst[mid], we do 2 comparisons (== 0, > search_value) plus the ones returned by the recursive call.
//Condition to check search value is less then list of mid element and return it.
if (lst[mid] > search_value)
{
return 2 + binary_search(search_value, lst, mid);
}
For values bigger than the pivot element, we do 3 comparisons (== 0, > search_value, < search_value) plus the ones returned by the recursive call.
//Condition to check search value is greater then list of mid element and return it.
else if (lst[mid] < search_value)
{
return 3 + binary_search(search_value, &lst[mid + 1], elements - mid - 1);
}
Otherwise, the value is equal to the pivot element, and we return 3 comparisons (== 0, > search_value, < search_value). This is the second base case.
else
{
return 3;
}
Related
My function works for the first 4 elements, but returns -1 for 12 and 14..even though there in the array.
I've tried changing some of the if statements and using .compare but haven't had any luck.
Any ideas?
Thanks
/** Searches the array anArray[first] through anArray[last]
for a given value by using a binary search.
#pre 0 <= first, last <= SIZE - 1, where SIZE is the
maximum size of the array, and anArray[first] <=
anArray[first + 1] <= ... <= anArray[last].
#post anArray is unchanged and either anArray[index] contains
the given value or index == -1.
#param anArray The array to search.
#param first The low index to start searching from.
#param last The high index to stop searching at.
#param target The search key.
#return Either index, such that anArray[index] == target, or -1.
*/
int binarySearch(const string anArray[], int first, int last, string target)
{
int index;
if (first > last)
index = -1; // target not in original array
else {
// If target is in anArray,
// anArray[first] <= target <= anArray[last]
int mid = first + (last - first) / 2;
if (anArray[mid] == target)
index = mid; // target found at anArray[mid]
else if (anArray[mid] > target)
// Point X
index = binarySearch(anArray, first, mid - 1, target);
else
// Point Y
index = binarySearch(anArray, mid + 1, last, target);
} // end if
return index;
}
int main()
{
const string v[6] = {"1","5","6","9","12","14"};
int index;
string searchItem = "12";
cout << "Searching For: " << searchItem << endl;
index = binarySearch(v, 0, 6, searchItem);
cout << "Element found at index " << index << endl;
system("pause");
return 0;
}
Problem is the fact that for binary search to work your array has to be sorted with the same criteria you use with your binary search. Array you provided is not sorted. You sorted numbers, but you have strings and they compare differently - lexicographically. Which means that "12" comes before "5" and so on. So you either need to convert strings to numbers before you compare, use proper data type (probably int) or change order of elements in your array accordingly.
Note: your function "works" for the first four elements because for single digit numbers lexicographical and numerical compare is the same.
Note2: you also seem to pass wrong number as last, your doc clearly says "SIZE - 1", which is equal to 5. (your array has indexes from 0 to 5, not to 6)
Problem is that you can't compare full strings like you compare numbers (although you can do that with chars according to ascii value). You have two options, the first and simpler one is defining a function to compare strings, something like:
int compareStrings (string a, string b) { // -1: a>b, 0: a=b, 1: a<b
if (a.length() == b.length()) {
if (a == b) return 0;
else for (int i = 0; i < a.length(); i++)
if (a[i] < b[i]) return 1;
else if (a[i] > b[i]) return -1;
}
else return (a.length() < b.length()? 1 : -1);
}
and then when you need to retrieve what string is bigger you could do:
int compResult = compareStrings (anArray[mid], target);
switch (compResult) {
case -1:
index = binarySearch(anArray, first, mid - 1, target); break;
case 1:
index = binarySearch(anArray, mid + 1, last, target); break;
}
The other one is creating a custom "wrapper" class for the strings such that you can override a comparing operator within it, but is a little bit more complicated, and the body of the functions would be pretty much the same, so I would suggest the former solution. But if you want to see how you could accomplish the latter of the solutions, here's a source:
https://www.geeksforgeeks.org/c-program-to-compare-two-strings-using-operator-overloading/
Hope it helps man
I have a code for "Minimum number of jumps to reach end of the array with its sequence using recursion". But I am not able to print the sequence. ( There is nothing in vector vec to print )
Any help will be appreciated.
Explanation :
I want to reach from 1st element ( i.e. 2) to
last element ( i.e. 4) of the array in minimum Jump.
How Jump will be :
1st element is 2. It means I can make upto 2 jumps in array. If I take 1st jump then I can reach 2nd element ( i.e. 3) or if I take
2nd jump then I can reach 3rd element (i.e. 1)
2nd element is 3 ,so I can make maximum 3 jumps. In 1st jump I can reach to 1 , in 2nd jump I can reach to 0 and in 3rd jump I can
reach to 4
In this way I want to reach from 1st element to last element of the array in minimum number of jumps.
So output will be like , from 1st element 2, I will jump to 3. Then from 3 I will jump to 4 (last element). So 2 Jumps. ( 2 - 3 - 4 )
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int jump(int arr[], int n, int start, vector<int> &vec)
{
if(start == n-1) // if start is the last element in array
return 0;
if( arr[start] == 0) // if array element is 0
return 0;
vector<int> vec1 = vec;
vector<int> vec2 = vec;
int minimum = INT_MAX;
for( int i = 1 ; i <= arr[start]; i++ )
{
vec1.push_back(start);
int _jump = 1 + jump( arr, n, start+i, vec1); // considering every jump
vec = (_jump < minimum) ? vec1 : vec2;
minimum = min(minimum, _jump);
}
return minimum;
}
int main()
{
int arr[] = { 2, 3, 1, 0, 4 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vec;
cout << "Number of jumps " << jump(arr, n, 0, vec) << endl;
cout<<"Sequence is "<<endl;
for( auto x : vec)
cout << x <<" ";
return 0;
}
output
Number of jumps 2
Sequence is
Expected output
Number of jumps 2
Sequence is 2 3 4
Here is an example that will set a vector where each index stores the correct next step in the sequence after visiting that index. I leave it to you to code following the sequence from the first element to the end, using the result vector. I also corrected this condition if( arr[start] == 0) to return "infinity" since if we visit this element, we cannot complete the sequence.
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int jump(int arr[], int n, int start, vector<int> &vec)
{
if(start == n-1) // if start is the last element in array
return 0;
if( arr[start] == 0) // if array element is 0
return INT_MAX - n;
int minimum = INT_MAX;
int step;
for( int i = 1 ; i <= arr[start]; i++ )
{
int _jump = 1 + jump( arr, n, start+i, vec); // considering every jump
if (_jump < minimum){
minimum = _jump;
step = start + i;
}
}
vec.at(start) = step;
return minimum;
}
int main()
{
int arr[] = { 2, 3, 1, 0, 4 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vec(n, -1);
cout << "Number of jumps " << jump(arr, n, 0, vec) << endl;
cout<<"Vector: "<<endl;
for( auto x : vec)
cout << x <<" ";
return 0;
}
Essentially, this is the minimal fix so that the sample data would works. I have not check all edge cases. For example, one might want to print something else than the value of INT_MAX is the end is not reachable.
Problem 1
You want to output values (i.e. 2, 3, 4 in your example) and not index (0, 1, 4). Thus you must push values instead of indexes.
vec1.push_back(arr[start]);
Problem 2
if(start == n-1) // if start is the last element in array
return 0;
This will not add the final value when the end is reached. You must add last value with:
vec.push_back(arr[start]);
Problem 3
if( arr[start] == 0) // if array element is 0
return 0;
A sequence that does not reach the end, would be considered to be very good. You should return a large value. Since _jump is 1 + return value of jump, the return value should be INT_MAX - 1 and minimum should also be initialized to that value for same reason.
Alternatively, you could return other values like n too instead.
Problem 4
Finally, the following condition is incorrect:
vec = (_jump < minimum) ? vec1 : vec2;
When the condition is not verified, it is vect2 that need to be copied in vec1 since the loop uses vect1.
Today I was trying to come up with a sorting algorithm and code it for practice. The one I decided on works like this. The algorithm first picks the zeroth element (let's call this the pivot) and iterates through the list. If an element is smaller than the pivot, then it is moved to somewhere on the list left to the pivot. After it finishes parsing through the list, it splits the list into two lists: the list to the left of the pivot and the list to the right of the pivot, and then recursively repeats the task on each side.
I tried looking through common comparison sorting algorithms in Wikipedia; I found methods such as quick sort, selection sort, and insertion sort, but none of these seem to be the one I'm looking for. My code is in C++, and I'll leave it here below if you want to take a look at it.
using namespace std;
template <typename T>
void sort(vector<T>& vec){
int size = vec.size();
if (size <= 1){ //this is the most basic case
return;
}
T pivot = vec[0];
int index = 0; //to help split the list later
for (int i = 1; i < size; ++i){ //moving (or not moving) the elements
if (vec[i] < pivot){
vec.insert(vec.begin(), vec[i]);
vec.erase(vec.begin() + i + 1);
++index;
}
}
if (index == 0){ //in case the 0th element is the smallest
vec.erase(vec.begin());
sort(vec);
vec.insert(vec.begin(), pivot);
}
else if(index == size - 1){ //in case the 0th element is the largest
vec.pop_back();
sort(vec);
vec.push_back(pivot);
}
//here is the main recursive portion
vector<T> left = vector<T>(vec.begin(), vec.begin() + index);
sort(left);
vector<T> right = vector<T>(vec.begin() + index + 1, vec.end());
sort(right);
//concatenating the sorted lists together
left.push_back(pivot);
left.insert(left.end(), right.begin(), right.end());
vec = left;
}
example of it in action:
int main() {
int arr[] = {-2, 5, 3, 1, 0, 12, -2, 5, 120, 0, 12, -100};
vector<int> vec = vector<int>(arr, arr + 12);
cout << "input: \n";
print(vec);
sort(vec);
cout << "\nafter sorting: \n";
print(vec);
return 0;
}
result:
input:
-2 5 3 1 0 12 -2 5 120 0 12 -100
after sorting:
-100 -2 -2 0 0 1 3 5 5 12 12 120
I need to identify the position of a variable from an integer array who has the following properties:
the sum of elements before this variable is equal with the sum of elements after this variable
if the variable doesn't exist, i will show a message.
For example, if x = {1,2,4,2,1}, the result is 4 with position 2, because 1 + 2 == 2 + 1.
Any suggestions? In this example it's easy
if((x[0]+x[1])==(x[3]+x[4]))
print position 2
But for n variables?
There are several ways to do this:
Brute force - n/2 passes:
Loop through the array.
For each element calculate the sum before and after that element.
If they match you found the element.
If the sum before becomes larger than the sum after, stop processing - no match found.
This is not really efficient for larger arrays.
1.5 passes:
Calculate the sum of all elements.
Divide that sum by 2 (half_sum).
Start summing the elements again from the beginning until you reach half_sum.
Check if you found a valid element or not.
Single pass (positive numbers only):
Keep two running sums: one from the beginning (sum1) and one from the end (sum2).
Set sum1 = first element and sum2 = last element.
Check for the smallest of the two and add the next/previous element to that.
Loop until the positions meet and check if the element is a valid result.
For each method you'll have to do a litlle check first to see if the array is not too small.
Special cases to consider:
Empty array: return false
Array with 1 element: return element
Array with 2 nonzero elements: return false
What with all zero's, or groups of zero's in the middle? (see Deduplicator's comment)
Negative elements: single pass version will not work here (see Cris Luengo's comment)
Negative elements in general: not reliable, consider +3 +1 -1 +1 -1 +3 +1 (see Deduplicator's comment)
Here is the O(n) solution.
Keep summing in in one variable from array beginning(left_sum) and keep deducing from the sum of elements except the first one using another(right_sum). When both becomes equal break the loop and print. Otherwise, show your msg.
#include <iostream>
#include <vector>
#include <numeric>
#include <cstddef>
int main()
{
std::vector<int> vec {1,2,4,2,1};
int left_sum = 0;
int right_sum = std::accumulate(vec.cbegin()+1, vec.cend(), 0);
bool Okay = false;
std::size_t index = 1; // start from index 1 until n-1
for( ; index < vec.size() - 1; ++index)
{
left_sum += vec[index-1];
right_sum -= vec[index];
if(left_sum == right_sum)
{
Okay = true;
break;
}
// in the case of array of positive integers
// if(left_sum > right_sum) break;
}
(Okay) ? std::cout << vec[index] << " " << index << std::endl: std::cout << "No such case!\n";
return 0;
}
Thanks for answers. I finally managed it. I used 3 for loops, and s0 is for sum before the element, and s1 is the sum after the element.
for(i=0;i<n;i++)
{s1=0;
s0=0;
for(int j=0;j<i-1;j++)
s0=s0+v[j];
for(int k=i;k<n;k++)
s1=s1+v[k];
if(s0==s1)
{cout<<endl<<"Position i="<<i;
x++;}
}
if(x==0)
cout<<"doesnt exist";
Well, do it in two steps:
Sum all elements.
From first to last:
If the sum equals the current element, success!
Subtract it twice from the sum (once for no longer being on the right, once for being on the left).
Use standard algorithms and range-for, and it's easily written:
auto first_balanced(std::span<const int> x) noexcept {
auto balance = std::accumulate(begin(x), end(x), 0LL);
for (auto&& n : x) {
if (balance == n)
return &n;
balance -= 2 * n;
}
return end(x);
}
It's just looping. You need to sum the elements before and after each index and just compare these two sums:
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<int> x = {1, 2, 4, 2, 1};
for ( unsigned idx = 0; idx < x.size(); ++idx )
if ( std::accumulate(x.begin(), x.begin() + idx, 0) == std::accumulate(x.begin() + idx + 1, x.end(), 0) )
std::cout << idx << std::endl;
return 0;
}
Trying to build a solution out of std::algorithm,
n+lg n instead of n+~n/2
Warning untested code.
bool HasHalfSum(int& atIndex, const std::vector<int>& v) {
std::vector<int> sum;
sum.reserve(v.size);
std::partial_sum(v.begin(), v.end(), std::back_iterator(sum));
// 1,3,7,9,10
int half = sum.back() / 2; // 5
auto found = std::lower_bound(sum.begin(), sum.end(), half);
if (found != sum.begin() && std::prev(found) == sum.back() - *found) {
index = std::distance(sum.begin(), found);
return true;
}
return false;
}
My Input is:
W[10] = {1, 3, 5, 7, 9, 12, 19, 22, 36, 63}
X[10] = {0};
M = 79;
I called the function by:
findSolution(0,0,177); <br>
Note: 177 is sum of all the elements inside W array.
void findSolution(int s, int k, int r) {
cout << "fn(" << s << " , " << k << ", " << r << " )" << endl;
X[k] = 1;
if (s + W[k] == M){
printArr(X);
}
else if (s + W[k] + W[k + 1] <= M) {
return findSolution(s + W[k], k + 1, r - W[k]);
}
if ((s + r - W[k] >= M) && (s + W[k + 1]) <= M){
X[k] = 0;
return findSolution(s, k + 1, r - W[k]);
}
}
Output:
fn(0 , 0, 177 )
fn(1 , 1, 176 )
fn(4 , 2, 173 )
fn(9 , 3, 168 )
fn(16 , 4, 161 )
fn(25 , 5, 152 )
fn(37 , 6, 140 )
fn(56 , 7, 121 )
The output given above is to track the function calls. The output ends here and doesn't go forward. What is wrong with my code. I am trying to print a subset which gives a desired sum = 79. The recursive call doesn't return back.
The problem with your solution is that it uses a greedy strategy (i.e. it does not "backtrack" after finding a suitable candidate).
Your algorithm checks for three conditions:
You found a solution,
A solution is possible if you add k-th element to the subset, or
A solution is possible if you replace k-1-st element with k-th.
This strategy does not exhaust all possibilities: for instance, it may not be possible to replace k-th element with k+1-st, but it may be possible to replace several elements ahead of k-th with k+1-st and obtain a solution. Your strategy is greedy, because when it discovers that an element could be added to a set (i.e. s + W[k] + W[k + 1] <= M) it takes that path, and never looks back (i.e. returns from that branch).
You can fix this by restructuring your code as follows:
Make your function return true when a solution is found, and false otherwise.
Keep your base case if (s + W[k] == M), and add a return true when a solution is found.
Check if it is possible to add k-th element to the set. If it is possible, add it, and try for the partial sum of s + W[k]
Check the return of the recursive invocation. If it is true, return true.
Otherwise, remove k-th element from the set, and make a second recursive invocation without the k-th element in the mix. Use the same partial sum of s.
Return the value of the last recursive invocation to the caller.
Now your algorithm is exhaustive, because for each element the algorithm tries to find a partial sum both when the element is part of the solution, and when the element is not part of the solution (i.e. O(2n) checks in all).
The recursive call is returning back; it is just doing so before you found a solution. This can happen if the last if is reached but fails. (Note that what looks like your base case, when you call printArr, does not necessarily stop the recursion.)
//code in c++ for return subset sum to k using recursion
int subsetSumToK(int input[], int n, int output[][50], int k) {
//as we are decreasing the value of k in int count1 recursive call, at a time value of k will be zero ,positive value and negative value also, so we will return only those subsets where the value of k is zero when the size of input array will become zero else we just return 0. In recursive calls we use two recursive calls, in first we are including the element, so as we including the element so now we have to find the value k - input[0](that included element) and store that element in o1 output array and in second recursive call as we are not including the element so just directily pass the call by input+1 and size-1 with o2 output array and the same value k.
if(n == 0){ //base case
if(k==0){
output[0][0] = 0;
return 1;
}else{
return 0;
}
}
int o1[1000][50]; //to store the output individually of two recusive calls
int o2[1000][50];
int count1 = subsetSumToK(input+1,n-1,o1,k-input[0]); //recursive calls
int count2 = subsetSumToK(input+1,n-1,o2,k);
for(int i=0;i<count1;i++){ //small calulations
for(int j=1;j<=o1[i][0];j++){
output[i][j+1] = o1[i][j];
}
output[i][0] = o1[i][0] +1;
output[i][1] = input[0];
}
for(int i=0 ; i<count2 ; i++){
for(int j=0 ; j<=o2[i][0] ; j++){
output[i + count1][j] = o2[i][j];
}
}
return count1 + count2;
}