Binary Search with Duplicates - c++

I am doing this particular exercise where I have to implement the Binary Search algorithm which returns the index of the first occurence of an element in a sorted array, if it contains duplicates. Since I am primarily working on my algorithmic skills in C++, I am only trying to do it in C++. Here is my code:
#include <iostream>
#include <cassert>
#include <vector>
using std::vector;
int binary_search(const vector<int> &a, int x, int n) {
int left = 0, right = n-1;
while(left<= right){
int mid = left + (right-left)/2;
if(x== a[mid]){
return mid;
}else if(a[mid]>x){
right = mid-1;
}else{
left = mid+1;
}
}
return -1;
}
int first_occurence(const vector<int>&a, int x, int n) {
int out = binary_search(a, x, n);
if(out !=-1){
for(int i = out;i>0&& a[i]==x;--i ){
out = i;
}
}
return out;
}
int main() {
int n;
std::cin >> n;
vector<int> a(n);
for (size_t i = 0; i < a.size(); i++) {
std::cin >> a[i];
}
int m;
std::cin >> m;
vector<int> b(m);
for (int i = 0; i < m; ++i) {
std::cin >> b[i];
}
for (int i = 0; i < m; ++i) {
std::cout << first_occurence(a, b[i], n) << ' ';
}
}
The first input to the program tells how many items the array should contain, the second is the enumeration of these elements, third line tells how many keys to search for and the final line are the individual keys. The output is the indices for the key or -1 when no such key is found.
My strategy is to use a function to find the index of a key. If it is found, then in case of duplicates, the first occurrence has to have a lower index. That is what the first_occurence() method does; keep looping back till the first occurence is found.
For the following input:
10
1 5 4 4 7 7 7 3 2 2
5
4 7 2 0 6
The output is:
-1 4 -1 -1 -1
Which is only correct for the key 7. I have been trying to debug this for quite some time but I can not figure out the problem.

returns the index of the first occurence of an element in a sorted array,
Your binary search algorithm requires that the data is sorted before you call it.
Example:
#include <algorithm>
#include <sstream>
int main() {
std::istringstream in(R"aw(10
1 5 4 4 7 7 7 3 2 2
5
4 7 2 0 6
)aw");
int n;
in >> n;
vector<int> a(n);
for (auto& v : a) {
in >> v;
}
std::sort(a.begin(), a.end()); // <- add this
// display the sorted result:
for (auto v : a) std::cout << v << ' ';
std::cout << '\n';
int m;
in >> m;
vector<int> b(m);
for (auto& v : b) {
in >> v;
}
for (auto v : b) {
std::cout << v << ' ' << first_occurence(a, v, n) << '\n';
}
}

Related

Trying to make a simple Array sorter with input numbers

I'm very new to C++ or even coding. I was trying to make a simple array sorter, where the I first input the number of elements that will be in the array and then input the elements. My outcome should be the array sorted in ascending order. I have not thought about the case if elements inserted are same. So I would love to get some help from you folks.
The main error that I'm facing is that only the first unsorted element is sorted while the rest are either interchanged or left the same.
int main(){
int x;
cout<<"Enter no. of elements"<<endl;
cin>>x;
int A[x];
for (int i = 0;i<x;i++){
cin>>A[i];
}
for(int i=0;i<x;i++)
cout<<A[i]<<",";
int count=0;
if(count <= (x-1)){
for (int i=0;i<(x-1);i++){
if(A[i]>A[i+1]){
int a;
a = A[i];
A[i] = A[(i+1)];
A[i+1] = a;
}
else if(A[i]<A[i+1])
count++;
}
}
cout<<"Sorted array:";
for(int i=0;i<x;i++)
cout<<A[i]<<",";
return 0;
}
You declared a variable length array
int x;
cout<<"Enter no. of elements"<<endl;
cin>>x;
int A[x];
because its size is not a compile-time constant.
However variable length arrays are not a standard C++ feature though some compilers have their own language extensions that support variable length arrays,
It is better to use the class template std::vector.
Another problem is that it seems you are trying to use the bubble sort method to sort the array. But this method requires two loops.
Here is a demonstration program that shows how the bubble sort algorithm can be implemented.
#include <iostream>
int main()
{
int a[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
const size_t N = sizeof( a ) / sizeof( *a );
for (const auto &item : a)
{
std::cout << item << ' ';
}
std::cout << '\n';
for (size_t last = N, sorted = N; not ( last < 2 ); last = sorted)
{
for (size_t i = sorted = 1; i < last; i++)
{
if (a[i] < a[i - 1])
{
// std::swap( a[i-1], a[i] );
int tmp = a[i - 1];
a[i - 1] = a[i];
a[i] = tmp;
sorted = i;
}
}
}
for (const auto &item : a)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
The program output is
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
Let us try the following method:
find the largest element in the array and move it to the end, by swapping with the last element;
repeat with the array but the last element, and so on.
To find the largest element in A[0..m-1], scan the array and keep an index to the largest so far, let l. This index can be initialized to 0.
// Move the largest to the end
int l= 0;
for (int i= 1; i < m; i++)
{
if (A[i] > A[l]) l= i;
}
// A[l] is the largest in A[0..m-1]
Swap(A[l], A[m-1]);
// A[m-1] is the largest in A[0..m-1]
To sort, repeat with decreasing m. You can stop when the subarray just holds one element:
// Sort
for (int m= n-1; m > 1; m--)
{
// Move the largest to the end
....
}
Writing the Swap operation and assembling the whole code is your task. Also check
correctness of the Move for the limit cases m= 0, 1, 2.
correctness of the Sort for the limit cases n= 1, 2, 3.
how you could instrument the code to verify that the Move does its job.
how you could instrument the code to verify that the Sort does its job.
what happens in case of equal keys.
Your code can be fixed a bit to make it working.
Just replace if (count <= (x - 1)) with while (count < (x - 1)) and also set count = 0; at start of loop, plus replace else if (A[i] < A[i + 1]) with just else. And your code becomes working!
Necessary fixes I did in code below. Also I did formatting (indents and spaces) to make code looks nicer. Rest remains same.
As I see you have a kind of Bubble Sort.
Try it online!
#include <iostream>
using namespace std;
int main() {
int x;
cout << "Enter no. of elements" << endl;
cin >> x;
int A[x];
for (int i = 0; i < x; i++) {
cin >> A[i];
}
for (int i = 0; i < x; i++)
cout << A[i] << ",";
int count = 0;
while (count < (x - 1)) {
count = 0;
for (int i = 0; i < (x - 1); i++) {
if (A[i] > A[i + 1]) {
int a;
a = A[i];
A[i] = A[(i + 1)];
A[i + 1] = a;
} else
count++;
}
}
cout << "Sorted array:";
for (int i = 0; i < x; i++)
cout << A[i] << ",";
return 0;
}
Input:
10
7 3 5 9 1 8 6 0 2 4
Output:
7,3,5,9,1,8,6,0,2,4,Sorted array:0,1,2,3,4,5,6,7,8,9,
If you are taking the size of array as input from user you have to create your array dynamically in c++ like
int *array=new int(x)
and after taking the inputs of the elements just run a nested loop from 0 to size and
the inner loop from 0 to size-1 and check if(A[i]>A[i+1]) if true then swap the values else continue

sorting vector leads to vector subscript out of range

I'm trying to sort the elements in a vector from smallest to biggest.
My algorithm:
Find the smallest number in the vector using least()
Find all occurrences of the smallest number in the vector and copy them into another vector named result
Delete those occurrences from the original vector
Repeat until all elements from the original vector have been deleted
As the title suggests, I'm getting vector subscript out of range error. I tried debugging by printing out the indexes, but they seem correct.
An example you could input could be:
5
5 5 4 3 2 1 2
The program should output: 1 2 2 3 4 5 5
Here's my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int least(vector<int> groups) {
int lowest = groups[0];
for (int i = 0; i < groups.size(); i++) {
//cout << i << endl;
if (groups[i] < lowest) {
lowest = groups[i];
}
}
return lowest;
}
vector<int> sort(vector<int> groups) {
vector<int> result;
while (groups.size() != 0) {
int smallest = least(groups);
//cout << smallest << endl;
for (int i = 0; i < groups.size(); i++) {
if (groups[i] == smallest) {
result.push_back(smallest);
}
//cout << i + " " + groups.size();
}
groups.erase(remove(groups.begin(), groups.end(), smallest), groups.end());
}
return result;
}
int main() //sort from least to greatest
{
int t, n, taxiCount = 0, numOfChildren = 0;
cin >> t;
vector<int> groups, result;
for (int i = 0; i < t; i++) {
cin >> n;
groups.push_back(n);
}
result = sort(groups);
//cout << result.size();
for (int i : result) {
cout << i + " ";
}
}
I know there are better ways to sort through a vector, but I'd like to stick to my way for now.

Permutations of a specific set of numbers from n to m

#include <iostream>
using namespace std;
int n, m, x[20], p[20];
void display(){
for(int i = 1 ; i <= n; ++i)
cout << x[i] << ' ';
cout << "\n";
}
void bkt(int k){
for(int i = n; i <= m; ++i)
if(!p[i]){
x[k] = i;
p[i] = 1;
if(k<n)
bkt(k+1);
else
display();
p[i] = 0;
}
}
int main()
{ cin >> n >> m;
bkt(1);
return 0;
}
This code should do the permutations from n to m, but it doesn't work and I don't know what I did wrong. I tried a set of examples like 4 and 6, and it should show
4 5 6
4 6 5
5 4 6
5 6 4
6 4 5
6 5 4
but it doesn't show anything in the console, just returns 0.
There's a number of issues with the code, but you can solve the problem in the following way:
cin >> n >> m; // get range
Then create a vector of the appropriate size
std::vector<int> v(m - n + 1);
and then fill it with the needed values
std::iota(std::begin(v), std::end(v), n);
and then generate all permutations in a loop
do {
// ...
} while(std::next_permuation(std::begin(v), std::end(v));

How to push elements to vector after it is cleared?

I am given an array of n elements and an integer K is given. I have to print the sub-array of K elements in reverse order.
I am storing the elements in a vector and increasing the count. Once the count equals K, print the vector in reverse order and clear all the elements of the vector.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t; // No of test cases
cin >> t;
while (t--)
{
// Size of array and The size of each group
int n, k;
cin >> n >> k;
int arr[n];
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
vector <int> my_nums;
int count = 0;
for (int i = 0; i < n; i++)
{
my_nums.push_back(arr[i]);
count++;
if (count == k)
{
for (auto it = my_nums.rbegin(); it != my_nums.rend(); ++it)
{
cout << *it << " ";
}
//Clear all elements in vector
my_nums.clear();
}
}
cout << endl;
}
return 0;
}
ex:
I/P:
1
8 3
1 2 3 4 5 6 7 8
Expected O/P:
3 2 1 6 5 4 8 7
Actual O/P:
3 2 1
You also need to reset the count. In addition to that, the my_nums vector should be cleared after printing the elements in it.
count++;
if (count == k)
{
for (auto it = my_nums.rbegin(); it != my_nums.rend(); ++it)
{
cout << *it << " ";
}
my_nums.clear(); // moved to here
count = 0; // --> reset here
}
But what happens when the count < k but i >= n ? That means you need to print the my_nums again after the for loop if my_nums is not empty, in order to get the complete result.
for (int i = 0; i < n; i++)
{
// above code
}
if (!my_nums.empty())
{
for (auto it = my_nums.rbegin(); it != my_nums.rend(); ++it)
{
cout << *it << " ";
}
}
Also, note that followings:
Why aren't variable-length arrays part of the C++ standard?
Why should I not #include <bits/stdc++.h>?
Why is "using namespace std;" considered bad practice?
Try to set "count = 0" at the end on the outer loop.

Generate subsets of elements from vector (NO NESTED LOOP)

Let v = {1,2,3,4,5,6}. I want to generate by using v the following sets:
1 2 3 4 5 6
2 1 3 4 5 6
3 1 2 4 5 6
4 1 2 3 5 6
5 1 2 3 4 6
6 1 2 3 4 5
To achieve this goal I am using the following code, with a nested for loop:
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v{1,2,3,4,5,6};
for(unsigned int i = 0; i < v.size(); i++)
{
cout << v[i] <<",";
for(unsigned int j = 0; j < v.size(); j++)
{
if(i != j)
cout << v[j] <<",";
}
cout << endl;
}
return 0;
}
Is there a better approach that can be used in order to generate the previous sets. At least not O(n^2).
For an input list of size n, your output will always consist of n*n numbers. You cannot do better than O(n^2).
However, it seems to me that you merely swap the first and the first element, then the first and the second, then the first and the third etc..
You can hide the inner loop which prints a particular subset with an algorithm though, like in
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v {1, 2, 3, 4, 5, 6};
for ( auto it = v.begin(); it != v.end(); ++it ) {
std::iter_swap( v.begin(), it );
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, "," ) );
std::cout << '\n';
}
}
To understand the lower bounds in your algorithm; Lets look at the transformation between the input and the output.
You are starting with a list of N elements and you end up with a list of [N x (N - 1)] elements.
Ignoring the logic to generate the output, the act of outputting itself is O(N * (N - 1)) => O(n2).
In other words, you are outputting NxN items per the intial input on N. This will be O(n2) by definition.
Here the inner loop is only used to print results:
int main()
{
vector<int> v{1,2,3,4,5,6};
for(unsigned int i = 0; i < v.size(); i++)
{
int t = v[0];
v[0] = v[i];
v[i] = t;
cout << v[0];
for(unsigned int j = 1; j < v.size(); j++)
{
cout << "," << v[j];
}
cout << endl;
}
return 0;
}