Bug in recursive divide et impera binary search - c++

I wrote a divide and conquer binary search, it works in all cases except for when I search for the first or the last number, where instead of giving me 0 and v.size()-1 as the result it gives me 1 and v.size()-2.
For example if I input n=5 and the vector {1; 2; 3; 4; 5} and search for 1 it returns me "1" instead of "0".
#include <iostream>
#include <vector>
using namespace std;
int binarySearch(std::vector<int> v, int nr, int left, int right)
{
int mij = (left + right) / 2;
if (v[mij] < nr){
binarySearch(v, nr, mij+1, right);
}
else if (v[mij] > nr){
binarySearch(v, nr, left, mij-1);
}
else if (v[mij] == nr){
return mij;
}
else return -1;
}
int main()
{
vector <int> v;
int n; cout << "n="; cin >>n;
for (int i = 0; i < n; i++){
int x;
cout << "v[" << i << "]=";
cin >> x;
v.push_back(x);
}
cout << binarySearch(v, 1, 0, v.size());
return 0;
}

Your code has undefined behavior because you do not return a value from your function in all cases. Your program might crash, do nothing, format your hard drive or give you the correct value - it's undefined what happens. In this case, your compiler knows exactly what the problem is and really wants to tell you, but you need to ask it: Turn on the warnings (e.g. -Wall in gcc or clang).
warning: control may reach end of non-void function [-Wreturn-type]
Currently, you do not return a value if you recurse, which is easily fixed:
int binarySearch(std::vector<int> v, int nr, int left, int right)
{
int mij = (left + right) / 2;
if (v[mij] < nr){
return binarySearch(v, nr, mij+1, right);
// ^^^^^^
}
else if (v[mij] > nr){
return binarySearch(v, nr, left, mij-1);
// ^^^^^^
}
else if (v[mij] == nr){
return mij;
}
else return -1;
}

Your binary search works fine but You sure you had passed inputs to the program correctly? input should be like this -
5
1 2 3 4 5
output
0
you can verify that here link to code

Related

What return type should I use for my function to print Fibonacci numbers?

I'm trying to write a function that prints all Fibonacci numbers between the range of x and y. I almost have it but I have no idea what return type to use for the function genFib(int min, int max){ I thought bool was right but when I tested the code, the line cout << genFib(5, 20) << endl;prints 5 8 13 0 adding the zero at the end. What return type should I use to avoid having a zero print at the end? This is all of my current code.
#include <iostream>
#include <cmath>
using namespace std;
bool perfectSquare(int x){
int s = sqrt(x);
return (s*s == x);
}
bool isFibonacci(int n){
return perfectSquare(5*n*n + 4) ||
perfectSquare(5*n*n - 4);
}
bool genFib(int min, int max){
int newMax = 0, newMin = 0;
if(min > max){
newMax = min;
newMin = max;
}else{
newMax = max;
newMin = min;
}
cout << "Fib numbers: ";
for(int i = newMin; i <= newMax; i++)
if(isFibonacci(i)) cout << i << " ";
return false;
}
int main(){
cout << genFib(5, 20) << endl;
return 0;
}
The last 0 you are seeing is there because you are returning false from genFib(), and then printing it. Because you are printing everything inside your genFib() method, you don't need to print the result from the method, or return anything from it. If you try the following, you won't print the result of genFib(), which is your trailing 0.
int main(){
int x = 372; // Simply a random number
genFib(5, 20);
return 0;
}
Since you also don't care about the return value of genFib(), you should return void instead of false. That would prevent anything from being printed if you do print the result of the method.

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';
}
}

Getting SIGSEGV (segmentation error) for the given problem. (Finding LCA of a generic tree)

So, I was trying to solve the below problem using the most basic method i.e. storing the paths and finding LCA.
My code is working fine on VSCode and giving the right output. But when submitting on SPOJ, it gives runtime error (SIGSEGV).
Problem Link: https://www.spoj.com/problems/LCA/
Problem Description:
A tree is an undirected graph in which any two vertices are connected by exactly one simple path. In other words, any connected graph without cycles is a tree. - Wikipedia
The lowest common ancestor (LCA) is a concept in graph theory and computer science. Let T be a rooted tree with N nodes. The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself). - Wikipedia
Your task in this problem is to find the LCA of any two given nodes v and w in a given tree T.
Sample Input:
1
7
3 2 3 4
0
3 5 6 7
0
0
0
0
2
5 7
2 7
Sample Output:
Case 1:
3
1
My Code:
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
using namespace std;
vector<vector<int>> edges;
bool storepath(int s, int d, vector<int>& path, vector<bool>& visited) {
if(s == d)
{
path.push_back(d);
return true;
}
else if(edges[s].size() == 1) {
if(s != d)
{
for(int i = 0; i < path.size(); i++)
if(path[i] == s) {
path.erase(path.begin() + i);
}
}
return false;
}
visited[s] = true;
path.push_back(s);
for(auto e: edges[s])
{
if(visited[e] == false)
{
bool ans = storepath(e, d, path, visited);
if(ans)
break;
}
}
}
int LCA(int a, int b)
{
if(a == b)
return a;
vector<int> path1, path2;
vector<bool> visited(edges.size(), false);
storepath(1, a, path1, visited);
visited.assign(edges.size(), false);
storepath(1, b, path2, visited);
int n = path1.size();
int m = path2.size();
int i = 0,j = 0;
while(i < n && j < m && path1[i] == path2[j]) {
i++;
j++;
}
return path1[i-1];
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
int Case = 1;
while(t--)
{
int n;
cin >> n;
edges.resize(n+1);
for(int i = 1; i <= n; i++)
{
int size, val;
cin >> size;
while(size--)
{
cin >> val;
edges[i].push_back(val);
edges[val].push_back(i);
}
}
int q;
cin >> q;
cout << "Case "<< Case << ":" << endl;
while(q--)
{
int a, b;
cin >> a >> b;
cout << LCA(a, b) << endl;
}
Case++;
edges.clear(); //added after igor's comment (forgot to add before but used while submitting)
}
return 0;
}
I think I'm not accessing any out of scope element so SIGSEGV should not occur.
Please tell me how can I fix and improve my code.
Some bugs are easy to find, when you know how to find them. The tools every programmer should know about are valgrind and -fsanitize. Remember to always compile with warnings enabled and fix them. Compiling your code with:
g++ -Wall -Wextra -fsanitize=undefined 1.cpp && ./a.out </tmp/2
results in a helpful warning:
1.cpp:38:1: warning: control reaches end of non-void function [-Wreturn-type]
38 | }
| ^
and a runtime error:
1.cpp:9:6: runtime error: execution reached the end of a value-returning function without returning a value
Your storepath doesn't return value.

When i recurse the following code on function prime the program crashes what is wrong in my code?

Whenever I try to recurse in the function prime, my program crashes at that step. I think the problem is passing the function small as a recursion. What am I doing wrong?
#include <iostream>
using namespace std;
int smallest(int n) {
for( int x = 2 ; x <= n/2 ; x++){
if (n%x==0) {
return x;
}
else {
return 0;
}
}
}
int prime(int n, int(*small)(int)) {
int factor;
if (n == 1){
return 0;
}
else {
factor = n % small(n);
cout << small(n) << endl;
return prime(factor , small);
}
}
int main() {
prime(50 , &smallest);
return 0;
}
As the comments point out, when small returns 0, you continue recursing when you shouldn't. This can be solved with a small update to your base case:
if (n <= 1){
return 0 ;
}
Furthermore, it's worth pointing out that as it stands, your prime function will never call itself more than once. When you call smallest, you are guaranteed to get a prime number!

Finding Longest Increasing Sub Sequence in a round table of numbers

I was recently working on the following problem.
http://www.codechef.com/problems/D2
The Chef is planning a buffet for the DirectiPlex inauguration party, and everyone is invited. On their way in, each guest picks up a sheet of paper containing a random number (this number may be repeated). The guests then sit down on a round table with their friends.
The Chef now decides that he would like to play a game. He asks you to pick a random person from your table and have them read their number out loud. Then, moving clockwise around the table, each person will read out their number. The goal is to find that set of numbers which forms an increasing subsequence. All people owning these numbers will be eligible for a lucky draw! One of the software developers is very excited about this prospect, and wants to maximize the number of people who are eligible for the lucky draw. So, he decides to write a program that decides who should read their number first so as to maximize the number of people that are eligible for the lucky draw. Can you beat him to it?
Input
The first line contains t, the number of test cases (about 15). Then t test cases follow. Each test case consists of two lines:
The first line contains a number N, the number of guests invited to the party.
The second line contains N numbers a1, a2, ..., an separated by spaces, which are the numbers written on the sheets of paper in clockwise order.
Output
For each test case, print a line containing a single number which is the maximum number of guests that can be eligible for participating the the lucky draw.
Constraints
1 ≤ N ≤ 10000
You may assume that each number number on the sheet of paper; ai is randomly generated, i.e. can be with equal probability any number from an interval [0,U], where U is some upper bound (1 ≤ U ≤ 106).
Example
Input:
3
2
0 0
3
3 2 1
6
4 8 6 1 5 2
Output:
1
2
4
On checking the solutions I found this code:
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#define LIMIT 37
using namespace std;
struct node {
int val;
int index;
};
int N;
int binary(int number, vector<int>& ans) {
int start = 0;
int n = ans.size();
int end = n - 1;
int mid;
if (start == end)
return 0;
while (start != end) {
mid = (start + end) / 2;
if (ans[mid] == number)
break;
if (ans[mid] > number)
end = mid;
else
start = mid + 1;
}
mid = (start + end) / 2;
return mid;
}
void display(vector<int>& list) {
cout << endl;
for (int i = 0; i < list.size(); i++)
cout << list[i] << " ";
cout << endl;
}
int maxsubsequence(vector<int>& list) {
vector<int> ans;
int N = list.size();
ans.push_back(list[0]);
int i;
// display(list);
for (i = 1; i < N; i++) {
int index = binary(list[i], ans);
/*if(index+1<ans.size())
continue;*/
if (list[i] < ans[index])
ans[index] = list[i];
if (list[i] > ans[index])
ans.push_back(list[i]);
// display(ans);
}
return ans.size();
}
int compute(int index, int* g) {
vector<int> list;
list.push_back(g[index]);
int itr = (index + 1) % N;
while (itr != index) {
list.push_back(g[itr]);
itr = (itr + 1) % N;
}
return maxsubsequence(list);
}
int solve(int* g, vector<node> list) {
int i;
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
return ret;
}
bool cmp(const node& o1, const node& o2)
{ return (o1.val < o2.val); }
int g[10001];
int main() {
int t;
cin >> t;
while (t--) {
cin >> N;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
cin >> g[i];
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
Can someone explain this to me. I am well aware of calculating LIS in nlog(n).
What I am not able to understand is this part:
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
and the reason behind sorting
sort(list.begin(),list.end(),cmp);
This algorithm is simply guessing at the starting point and computing the LIS for each of these guesses.
The first value in a LIS is likely to be a small number, so this algorithm simply tries the LIMIT smallest values as potential starting points.
The sort function is used to identify the smallest values.
The for loop is used to check each starting point in turn.
WARNING
Note that this algorithm may fail for certain inputs. For example, consider the sequence
0,1,2,..,49,9900,9901,...,99999,50,51,52,...,9899
The algorithm will try just the first 37 starting points and miss the best starting point at 50.
You can test this by changing the code to:
int main() {
int t;
t=1;
while (t--) {
N=10000;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
if (i<50)
g[i]=i;
else if (i<150)
g[i]=9999-150+i;
else
g[i]=i-100;
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
This will generate different answers depending on whether LIMIT is 37 or 370.
In practice, for randomly generated sequences it will have a good chance of working (although I don't know how to compute the probability exactly).