Binary Search in C++: Ascending + Descending Ordered Arrays - c++

So I am trying to make a binary sort algorithm for my c++ class, but I keep getting a segmentation fault when my binarySearch function runs. No matter how hard me and my roommate look at it, we cant find the issue. Any help would be greatly appreciated.
int binarySearch(int arr[], int k, int first, int last)
{
if(arr[first] <= arr[last])
{
int mid = (first + last) / 2;
if(k == arr[mid])
{
return mid;
}
else if (k < arr[mid])
{
return binarySearch(arr, k, first, mid-1);
}
else return binarySearch(arr, k, mid+1, last);
}
else if(arr[first] >= arr[last])
{
int mid = (first + last) / 2;
if(k == arr[mid])
{
return mid;
}
else if (k < arr[mid])
{
return binarySearch(arr, k, mid+1, last);
}
else return binarySearch(arr, k, first, mid-1);
}
else return -1;
}
After fixing the segmentation fault, I noticed I must have an error somewhere in my logic because the program keeps outputting that the key was unable to be found even though it exists in the array.

Your code works actually, if the element you are searching for is in the array. However, it does not catch incorrect input.
When calling the function, make sure that:
first and last are between 0 and (array length - 1)
first < last
eg: if the array has 10 elements, first and last must be between 0 and 9.
Try this:
int main() {
int a[] = {134, 232, 233, 234, 587, 623, 793, 802, 963, 1074};
int b[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
int na = binarySearch(a, 587, 0, 9);
int nb = binarySearch(b, 3, 0, 9);
printf("na: %d\n", na); // prints 'na: 4'
printf("nb: %d\n", nb); // prints 'nb: 7'
}
If the element you are searching for is not in the array,
then the recursion does never terminate,
you can fix that by adding the following to the head of binarySearch():
if (first == last && k != arr[first])
return -1;

Not a major concern, but to prevent overflow it is usual to rewrite int mid = (first + last) / 2; as int mid = first + (last-first)>>1;
It also seems that you will never hit the line return -1 (the first two conditionals take care of all possible orderings)
An implementation (for strictly increasing, or decreasing array) could look like that
#include <cassert>
int binarySearch(int* array, int k, int l, int h, bool asc)
{
if (l>h)
return -1;
int m = l + ((h - l) >> 1);
if (array[m] == k)
return m;
else
{
if (array[m]>k)
return binarySearch(array, k, (asc ? l : m + 1), (asc ? m - 1 : h),asc);
else
return binarySearch(array, k, (asc ? m + 1 : l), (asc ? h : m - 1),asc);
}
}
int main()
{
int ascArray[7] = {1, 2, 3, 4, 5, 6, 7};
int descArray[7] = {7, 6, 5, 4, 3, 2, 1};
assert(binarySearch(ascArray, 7, 0, 6, ascArray[0] < ascArray[1]) == 6);
assert(binarySearch(descArray, 7, 0, 6, descArray[0] < descArray[1]) == 0);
}

instead of using if else if, you can try while loop:
int mid = (first + last)/2;
while(first<=last && arr[mid]!=k){
if(arr[mid]<k)
first=mid+1;
else
last=mid-1;
mid = (first + last)/2;
}
if(arr[mid] == k){
std::cout<<"Found"<<std::endl;
}else{
std::cout<<"Not Found"<<std::endl;
}
Instead you can use vector, that makes it very easy:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int arrint[] = {3,5,2,1,7,6,9,4,8,10};
vector<int> vector1(arrint,arrint+10);
sort(vector1.begin(),vector1.end());
int n;
cout<<"Enter element to search: ";
cin>>n;
cin.ignore();
cout<<endl;
if(binary_search(vector1.begin(),vector1.end(),n)){
cout<<"Found: "<<n<<endl;
}else{
cout<<n<<" Not Found"<<endl;
}
//cin.get();
return 0;
}

Make sure first>=last. I think the crash is because you don't find the element in the array.

Related

Facing problem of process exited with return value 3221225725

I am getting this-' process exited with return value 3221225725 ' for some of the values. I am facing problem to find where i goes wrong. Please someone help me. Here's the code-
#include<iostream>
using namespace std;
int binsearch(int a[],int find,int l,int u,int n);
int main()
{
int a[10]={1,54,76,89,123,145,198,230,345,654};
int n=sizeof(a)/sizeof(a[0]);
int find,l=0,u=n-1,x;
cout<<"Enter number which you want to find"<<endl;
cin>>find;
x= binsearch(a,find,l,u,n);
if(x==0)
cout<<"Element is not found";
else
cout<<"Element is present at "<<x;
}
int binsearch(int a[],int find,int l,int u,int n){
if(n==1)
{
if(find==a[l])
return l;
else
return 0;
}
else
{
int mid=l+u/2;
if(a[mid]==find)
return mid;
else if(a[mid]<find)
return binsearch(a,find,mid+1,u,n);
else
return binsearch(a,find,l,mid-1,n);
}
}
3221225725 is 0xC00000FD in hex, which is Microsoft's code for a stack overflow.
You have written a recursive binsearch() function, so that's the obvious place to look for a problem.
Your recursion stops only if n == 1 or if a[mid]==find. But in your code, n will never equal 1, because it is passed unchanged in each recursive call. That's a bug (there may be more, I haven't checked). So you will get a stack overflow if you enter a number that isn't in the array, because in that case a[mid]==find will never be true either.
My advice would be to eliminate n from your code. n is always equal to u - l + 1, so there is no need for a separate variable. If you need to know the value of n, you can always calculate it from l and u.
When you enter a number that is not found, binsearch will call itself over and over again until the stack overflows because your terminating condition if(n==1) will never be true since you call binsearch with the same n all the time. n isn't needed since you have both l and u so just make it int n = u - l + 1;.
mid=l+u/2 is also incorrect. It's the same as mid = u/2 + l. You want mid = (l + u) / 2.
Also, if you search for 1 it'll return the index 0 but you treat 0 as "not found". Since you use a signed integer for indexing, you could return -1 to signal that the number wasn't found.
Example:
#include <iostream>
#include <iterator> // std::size()
int binsearch(int a[], int find, int l, int u) {
int n = u - l + 1;
if(n == 1) {
if(find == a[l])
return l;
else
return -1;
} else {
int mid = (l + u) / 2;
if(a[mid] == find)
return mid;
else if(a[mid] < find)
return binsearch(a, find, mid + 1, u);
else
return binsearch(a, find, l, mid - 1);
}
}
int main() {
int a[] = {1, 54, 76, 89, 123, 145, 198, 230, 345, 654};
int l = 0, u = std::size(a) - 1, x;
std::cout << "Enter number which you want to find\n";
if(int find; std::cin >> find) {
x = binsearch(a, find, l, u);
if(x == -1)
std::cout << "Element is not found";
else
std::cout << "Element is present at " << x;
std::cout << '\n';
}
}

How do I recursively enumerate all subsets adding to a given sum?

When I try to get the output, it shows same solutions with same element for few times before moving on to another one.
I want to get different solutions from the array that is equal to sum
For instance,
Solution 1 = 14, 8
Solution 2 = 14, 5, 3
Solution 3 = 13, 9
and so on but what I get is repeated solutions for the sum of 22. Im getting this error
Solution : { 14, 8 }
Solution : { 14, 8 }
Solution : { 14, 8 }
Solution : { 14, 8 }
Solution : { 14, 8 }
Solution : { 14, 8 }
Solution : { 14, 5, 3 }
Solution : { 13, 6, 3 }
Solution : { 13, 5, 4 }
Solution : { 13, 5, 4 }
Solution : { 13, 6, 3 }
Solution : { 13, 5, 4 }
Solution : { 13, 5, 4 }
and another 20 lines of the same output.
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <vector>
#include <algorithm>
using namespace std;
void printSolution(int* r, int k)
{
cout << " Solution : { ";
for (int j = 0; j < k; j++)
{
cout << r[j];
if (j < k - 1)
cout << ", ";
}
cout << " }" << endl;
}
bool subSetSum(int* a, int n, int i, int sum, int* r, int k)
{
if (sum == 0)
printSolution(r, k);
if (i > n)
return false;
r[k++] = a[i];
if (subSetSum(a, n, i + 1, sum - a[i], r, k))
return true;
k -= 1;
subSetSum(a, n, i + 1, sum, r, k);
}
int descendingOrder(const void* a, const void* b)
{
int* p1 = (int*)a;
int* p2 = (int*)b;
return *p2 - *p1;
}
int main()
{
int a[] = { 4, 10, 7, 12, 6, 10, 10, 8, 5, 13, 13, 11, 3, 14 };
int n = 14;
int* r = new int[n];
int k = 0;
qsort(a, n, sizeof(int), descendingOrder);
cout << " Array a[] = ";
for (int count = 0; count < n; count++)
{
cout << a[count] << " ";
}
cout << endl << endl;
int sum = 22;
bool solFound = subSetSum(a, n, 0, sum, r, k);
return 0;
}
You have several errors in your subsetSum function. First of all, your version has a branch where it doesn't return a value. This could have been easily mitigated by enabling compiler warnings.
Second, you have an off-by-one error in your termination condition. i==n is an invalid index, so you will run-over your buffer end.
The reason you get the same result several times is because there are multiple paths to the same result. This is most likely related to the missing return statement.
The fix for this is to terminate the recursion descend once you find a match (when you print it). It is guaranteed that you will not find additional results (unless there are entries <= 0 in your input).
bool subSetSum(int* a, int n, int i, int sum, int* r, int k)
{
if (sum == 0) {
printSolution(r, k);
return true;
}
if (i >= n)
return false;
r[k] = a[i];
bool found = subSetSum(a, n, i + 1, sum - a[i], r, k + 1);
found = subSetSum(a, n, i + 1, sum, r, k) || found;
return found;
}
Please note that this still finds duplicate solutions for duplicate values in your input array (such as 10). You can easily add a check to skip duplicate values in the second recursion call to subSetSum by not passing i + 1 but by finding the next index that is not duplicate. Since you already sorted your input, this can be done by incrementing i until it points to a different value.
Also it should be pointed out that this is quite unidiomatic C++. A better interface to your subsetSum would look like this:
template <typename T, typename ConstIterator>
bool subSetSum(ConstIterator begin, ConstIterator end, T sum, std::vector<T>& buf);
template <typename T, typename ConstIterator>
bool subSetSum(ConstIterator begin, ConstIterator end, T sum) {
std::vector<T> buf;
return subSetSum(begin,end,std::move(T),buf);
}
First of all, no effeciency can be applied here (probably), since this question is NP complete, which means it is probably not solvable in polynomial time.
About the solution, I'll attach a code:
using SolutionT = std::vector<std::set<std::size_t>>;
SolutionT subsetSum(const std::vector<int>& array, int requiredSum, std::size_t index, int currentSum)
{
if (currentSum > requiredSum) { // Remove it if negative integers are present
return {};
}
if (index >= array.size()) {
return {};
}
if (requiredSum == currentSum + array[index]) {
std::set<std::size_t> indices{};
indices.insert(index);
SolutionT solution;
solution.emplace_back(std::move(indices));
return solution;
}
auto includedSolutions = subsetSum(array, requiredSum, index + 1, currentSum + array[index]);
for (auto& solution : includedSolutions) {
solution.insert(index);
}
auto excludedSolutions = subsetSum(array, requiredSum, index + 1, currentSum);
std::copy(std::make_move_iterator(includedSolutions.begin()),
std::make_move_iterator(includedSolutions.end()),
std::back_inserter(excludedSolutions));
return excludedSolutions;
}
SolutionT subsetSum(const std::vector<int>& array, int requiredSum)
{
return subsetSum(array, requiredSum, 0, 0);
}
The code is rather complicated since you need an exponential number of elements, so it is very hard to do without C++ containers.

Longest Increasing Sub-sequence within a vector using recursion?

So for my lab I'm attempting to find the longest sequence of numbers within a given vector.
for example, if the numbers you had were [5, 15, 16, 4, 8, 9, 10] the longest increasing sub-sequence would be 4, the 4, 8, 9, 10 portion. I have to be able to find this without using loops and using recursion and I've gotten this far, but I can't quite figure out how to hold a variable for the longest sequence and also have a variable for the temporary longest sequence, it just has to return the integer value of the length of the sequence, not the sequence itself. Thank you and any help or critiques are appreciated!
int increasing_sequence_recursive(std::vector<int> &numbers, int startIdx) {
if (startIdx == numbers.size()) {
return '/0';
} else if (numbers[startIdx] < numbers[startIdx + 1]) {
int tempSeq = 1 + increasing_sequence_recursive(numbers, startIdx + 1);
return tempSeq;
}
return increasing_sequence_recursive(numbers, startIdx + 1);
}
EDIT:
'''
int maxTemp(std::vector<int> &numbers, int startIdx, int maxSoFar) {
if (startIdx == numbers.size()) {
return maxSoFar;
} else if (numbers[startIdx] < numbers[startIdx + 1]) {
int temp = 1 + maxTemp(numbers, startIdx + 1, maxSoFar);
if (temp > maxSoFar) {
maxSoFar = temp;
}
temp = 1;
} else {
return maxTemp(numbers, startIdx + 1, maxSoFar);
}
}
'''
I created this helper function to do the main recursion but for some reason the temp value is never resetting so the value is basically the added length of both sequences.

Function to return count of duplicate numbers in sorted array

I want to return the number of duplicate values in a sorted array.
For example: a = { 1, 1, 2, 3, 4, 4 }, fratelli(n) should return 2. (They are 1, 1 and 4, 4)
I attempted to use a recursive approach, but it doesn't work. It Always give me 4.
I'm asking if someone please could help me understand better this methods of programming. Thanks a lot!
The function:
#include <iostream>
using namespace std;
int fratelli(int a[], int l, int r)
{
if (l == r) return 0;
else
{
int c = (l+r) / 2;
int n = fratelli(a, l, c) + fratelli(a, c+1, r);
if (a[l] == a[l+1]) n++;
return n;
}
}
int main()
{
const int _N = 11;
int array[_N] = { 1, 1, 2, 3, 5, 5, 7, 8, 8, 11, 12 };
cout << "\n" << fratelli(array, 0, _N-1);
return 0;
}
You have an error on this line:
if (a[l] == a[l+1]) n++;
The check should be at index c not at l. Apart from this your code seems alright to me.

Function to check if any combination of numbers in a vector will add up to an int?

To start with, I'm looking for something simple and easy to understand rather than the most efficient.
I am trying to create a function that will take in a vector, and an int. The function should return true if any numbers in the vector can add up to the int.
The vector will start with the numbers 1,2,3,4,5,6,7,8,9,10 in it, and throughout the program numbers will be removed. There will be no duplicates of numbers.
The int can be any number from 2 through 12.
Some examples:
vector = { 2,3,4,5 } int = 7; function returns true because 3 + 4 = 7.
vector = { 1,5,8 } int = 7; function returns false because none of these numbers can add to 7.
vector = { 3,6 } int = 3; function returns true because 3 = 3.
vector = { 5 } int = 2; function returns false because five cannot add to two.
This is the very last function I need to finish a game I am working on. I feel like I'm missing an easy solution, but I'm not sure. Can anyone show me how to do this, or point me in the right direction of how to solve this problem? Thank you in advance.
Given the additional information in the comments, the following function should do (I'm assuming the same number cannot be used twice in the sum):
typedef std::vector<int>::iterator iter;
bool contains_sum(iter begin, iter end, int sum)
{
while (begin != end)
{
--end;
if (*end > sum)
continue;
if (contains_sum(begin, end, sum - *end))
return true;
}
return sum == 0;
}
Isn't this a case of the knapsack problem?
See also: subset sum
What you need to do is to find all possible combinations and then check if any of those have the right sum. A double-recursive function can make the check.
bool canFormSum(vector<int>::iterator rest, vector<int>::iterator end,
int sumSoFar, int targetSum)
{
if(rest == end) return false;
if(sumSoFar + *rest == targetSum) return true;
if(canFormSum(rest + 1, end, sumSoFar, targetSum)) return true;
if(sumSoFar + *rest > targetSum) return false;
return canFormSum(rest + 1, end, sumSoFar + *rest, targetSum);
}
It's a nice example of recursive calculation - but for anything but small vectors it has horrible performance.
For the general cases (size of vector > 10),
Let f({a, b, c, d, ...}, e) be the result of whether any number in the set {a, b, c, d, ...} be equal to e.
Observe that, if e = x + y + z + ..., then either (1) a is in the set of {x, y, z, ...}, or (2) a is not in the set of {x, y, z, ...}. That means, we have the recursive definition:
f({a, etc...}, e) = f({etc...}, e-a) || f({etc...}, e)
And obviously, if the sum is 0, the relation is always true by not including any element from the set:
f({...}, 0) = true
and if the set is empty and the sum is nonzero, the relation is always false:
f({}, e) = false (if e != 0)
These are the base cases of the recursion.
Edit: See also the Subset sum problem for further discussion.
Just to compare my (C) solution with celtschk (c++) solution. (Basically compared the approach, not the languages)
#include <iostream>
#include <vector>
using namespace std;
int counter = 0;
typedef std::vector<int>::iterator iter;
bool contains_sum(iter begin, iter end, int sum)
{
counter ++;
while (begin != end)
{
--end;
if (contains_sum(begin, end, sum - *end))
return true;
}
return sum == 0;
}
int main () {
vector<int> data;
for (int i = 1; i <= 30; i ++) {
data.push_back(i);
}
int target = 77;
if (contains_sum (data.begin(), data.end(), target)) {
cout << "possible\n" << counter;
} else {
cout << "not possible\n << counter";
}
}
output
possible
268304387
Means nearly 270 million calls of recursive method
Now my approach
#include<stdio.h>
#include<stdlib.h>
int counter;
int check (int* in, int sum) {
counter ++;
while (1) {
int act = *in++;
if (act == 0) return 0;
int rest = sum - act;
if (rest == 0) return 1; // found;
if (rest > 0) {
if (1 == check (in, rest)) return 1; // found
}
}
return -1;
}
void pr (int* in, int sum) {
counter = 0;
int res = check (in, sum);
while (*in) {
printf ("%d ", *in ++);
}
if (res == 0) {
printf(" != %d %d\n", sum, counter);
} else {
printf(" == %d %d\n", sum, counter);
}
}
int main () {
int p0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,
0};
pr (p0, 77);
int p1[] = {2,3,4,5, 0};
pr (p1, 7);
int p2[] = {1,5,8, 0};
pr (p2, 7);
int p3[] = {3,6, 0};
pr (p3, 3);
int p4[] = {5, 0};
pr (p4, 2);
int p5[] = {1, 100, 6, 0};
pr (p5, 7);
return 0;
}
and this is the output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29 30 == 77 22
2 3 4 5 == 7 4
1 5 8 != 7 4
3 6 == 3 1
5 != 2 1
1 100 6 == 7 2
Ups, just 22 iterations!
Anyone may decide which approach to consider more "elegant"
You have to try all possible combination until you found a solution. SUch problems would be good for the language "prolog". So we have to simulate backtracking.
this code is in the end c.
#include<stdio.h>
int check (int* in, int sum) {
while (1) {
int act = *in++;
if (act == 0) return 0;
int rest = sum - act;
if (rest > 0) { // test in the order of expected likelyhoods
if (1 == check (in, rest)) return 1; // found
}
// if (rest < 0) return 0; // minor optimization, valid if list is ordered ascendant
if (rest == 0) return 1; // found;
}
//return -1; // only necessary on poor compilers
}
void pr (int* in, int sum) {
int res = check (in, sum);
while (*in) {
printf ("%d ", *in ++);
}
if (res == 0) {
printf(" != %d\n", sum);
} else {
printf(" == %d\n", sum);
}
}
int main () {
int p1[] = {2,3,4,5, 0};
pr (p1, 7);
int p2[] = {1,5,8, 0};
pr (p2, 7);
int p3[] = {3,6, 0};
pr (p3, 3);
int p4[] = {5, 0};
pr (p4, 2);
int p5[] = {1, 100, 6, 0};
pr (p5, 7);
return 0;
}
proven to run
2 3 4 5 == 7
1 5 8 != 7
3 6 == 3
5 != 2
1 100 6 == 7