binary_search in c++ unexpected behaviour - c++

The following snippet is returning me 0. I expected it to be 1. What's wrong going on here?
#include <iostream>
#include <iterator>
#include <ostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
vector<int> v;
int arr[] = {10,20,30,40,50};
v.push_back(11);
v.push_back(22);
copy(arr,arr + sizeof(arr)/sizeof(arr[0]),back_inserter(v)); // back_inserter makes space starting from the end of vector v
for(auto i = v.begin(); i != v.end(); ++i){
cout << *i << endl;
}
cout << endl << "Binary Search - " << binary_search(v.begin(), v.end(), 10) <<endl; // returns bool
}
I am using gcc /usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper

I ran the program and saw this:
11
22
10
20
30
40
50
Binary Search - 0
Your array is not sorted, therefore, binary search fails. (it sees 11 in the first position, and concludes 10 does not exist here)
You either want to ensure the array is sorted before binary searching or use the regular std::find.

binary_search says:
Checks if the sorted range [first, last) contains an element equal to
value. The first version uses operator< to compare the elements, the
second version uses the given comparison function comp.
Your list is not sorted, it contains the elements 11 and 22 prior to 10.

Your array is not sorted, so binary_search got undefined behavior. Try std::find instead
bool found = std::find(v.begin(), v.end(), 10) != v.end()
ยง25.4.3.4 of the C++11 standard (3242 draft)
Requires: The elements e of [first,last) are partitioned with respect to the expressions e < value and !(value < e) or comp(e,
value) and !comp(value, e). Also, for all elements e of [first, last),
e < value implies !(value < e) or comp(e, value) implies !comp(value,
e).

"Unexpected behavior"? There's nothing unexpected here.
The whole idea of binary search algorithm is taking advantage of the fact that the input array is sorted. If the array is not sorted, there can't be any binary search on it.
When you use std::binary_search (as well as all other standard binary search-based algorithms), the input sequence must be sorted in accordance with the same comparison predicate as the one used by std::binary_search. Since you did not pass any custom predicate to std::binary_search, it will use the ordering defined by < operator. That means that your input Sequence of integers must be sorted in ascending order.
In your case the input sequence does not satisfy that requirement. std::binary_search cannot be used on it.

Related

How to find unique values in a vector c++

I am trying to solve a coding problem where I am to check and see if a vector has unique values and if it does then return true else false.
So Far I thought of using a nested loops where you would compare the first to the last, but I am wanted to know if C++ has anything else then doing a o(n^2) type iteration. I saw that c++ has a unique function, but that would delete the unique value.
Example 1:
Input: nums = [1,2,3,1]
Output: true
Example 2:
Input: nums = [1,2,3,4]
Output: false
std::unique checks for consecutive duplicates and moves them to the end of the range. It does not remove them from the vector. Anyhow you can make a copy. It also returns an iterator to the end of the range of unique values (that are now in the front of the vector):
#include <iostream>
#include <vector>
#include <algorithm>
bool only_unique(std::vector<int> v) {
std::sort(v.begin(),v.end());
return std::unique(v.begin(),v.end()) == v.end();
}
int main(){
std::cout << only_unique({1,2,3,1});
std::cout << only_unique({1,2,3,4});
}
If you don't want to use the additional memory you can change the argument to a reference. Currently, only_unique leaves the parameter unmodified. Even if the vector is passed by reference the duplicates will still be present (just at a different position). This has O(n log n) complexity.
you need to create "set" structure,
it makes it possible to insert values from vector and does not insert the duplicates,
so you can check if the size of the set and the vector match or not.
set<int> st;
for (auto i : nums)
st.insert(i);
return st.size() == nums.size();

upper_bound and find giving different results

I am new to STL and used find() and upper_bound() functions on vector to find the position of 6 . The code is given below
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> sam ={1,2,5,3,7,8,4,6};
int f=upper_bound(sam.begin(), sam.end(), 6)- sam.begin();
vector<int>::iterator it;
it =find (sam.begin(), sam.end(), 6);
int d=it - sam.begin() ;
cout<<d<<" "<<f<<endl;
return 0;
}
The output when you run the code is 7 4 ,while I expected it to be 7 7 .
What am I doing wrong ?
cppreference.com for std::upper_bound() explains it nicely (emphasis mine):
Returns an iterator pointing to the first element in the range [first, last) that is greater than value, or last if no such element is found.
The range [first, last) must be partitioned with respect to the
expression !(value < element) or !comp(value, element), i.e., all
elements for which the expression is true must precede all elements
for which the expression is false. A fully-sorted range meets this
criterion.
In your case, you have a 7 (greater than 6, at index 4) appearing before a 4 (which is equal or less than 6), so the precondition is not met.
The idea of std::upper_bound() and its companions is to quickly do binary searches in sorted arrays. As opposed to linear search as in std::find(), it only needs O(log(n)) time complexity instead of O(n).

Use of std::greater

I am curious about the use of std::greater.
When used with sort, it outputs the numbers in descending order. But when used with priority_queue, numbers are output in ascending order. Why so?
Example:
#include <iostream> // std::cout
#include <functional> // std::greater
#include <algorithm> // std::sort
#include <queue> // std::priority_queue
int main () {
int numbers[]={20,40,50,10,30};
std::priority_queue<int, std::vector<int>, std::greater<int>> pq (numbers, numbers+5);
std::sort(numbers, numbers + 5, std::greater<int>());
while(!pq.empty()){
std:: cout << pq.top() << ' ';
pq.pop();
}
std::cout << '\n';
for (int i=0; i<5; i++)
std::cout << numbers[i] << ' ';
return 0;
}
The output of above code is:
10 20 30 40 50
50 40 30 20 10
Or similar lines,
std::priority_queue<int, std::vector<int>, std::greater<int> > creates a min heap whereas std::priority_queue<int, std::vector<int>, std::less<int> > creates a max heap. Could have been the other way round. Why is it so?
Citing std::priority_queue at cppreference [emphasis mine]
A priority queue is a container adaptor that provides constant time
lookup of the largest (by default) element, at the expense of
logarithmic insertion and extraction.
A user-provided Compare can be supplied to change the ordering, e.g.
using std::greater<T> would cause the smallest element to appear as
the top().
So this order is expected, and does not really relate to how std::sort sorts element based on a supplied binary comparison function.
Sorts the elements in the range [first, last) in ascending
order.
...
Parameters
first, last - the range of elements to sort
policy - the execution policy to use. See execution policy for details.
comp - comparison function object (i.e. an object that satisfies the
requirements of Compare) which returns true if the first argument
is less than (i.e. is ordered before) the second.
As std::greater will return true if its first argument is greater than its second one, we expect the elements to be sorted in descending order when using std::sort with std::greater as function object for performing comparisons.
I.e., std::greater just happens to be the function object used for performing comparisons in these two different contexts of your example.

Is there any library for binary Search in C++

Is there any pre-implemented library in C++ for fast search in a list like binary search? Does the normal list support any kind of find function? Or any function like exists?
I have a list of objects, I want to store them in a list, but not duplicate elements. I want to notice whether or not the new element exists in the list and do a proper action.
There is std::lower_bound() which finds a suitable position in any bidirectional sequence using O(log n) comparisons. Since linked lists don't support random access traversal is O(n). You can use std::binary_search() if you are only interested whether there is a suitable object but this algorithm isn't useful if you are interested in locating the object. Of course, a precondition for std::lower_bound() and std::binary_search() is that the sequence is sorted.
I believe you are looking for the C++ <algorithm> library. It includes a function called binary_search.
An example of it is provided on the page and echoed here:
// binary_search example
#include <iostream> // std::cout
#include <algorithm> // std::binary_search, std::sort
#include <vector> // std::vector
bool myfunction (int i,int j) { return (i<j); }
int main () {
int myints[] = {1,2,3,4,5,4,3,2,1};
std::vector<int> v(myints,myints+9); // 1 2 3 4 5 4 3 2 1
// using default comparison:
std::sort (v.begin(), v.end());
std::cout << "looking for a 3... ";
if (std::binary_search (v.begin(), v.end(), 3))
std::cout << "found!\n"; else std::cout << "not found.\n";
// using myfunction as comp:
std::sort (v.begin(), v.end(), myfunction);
std::cout << "looking for a 6... ";
if (std::binary_search (v.begin(), v.end(), 6, myfunction))
std::cout << "found!\n"; else std::cout << "not found.\n";
return 0;
}
If you are writing real C++ code you can use the algorithm standard library.
In it there is the find function which grant to you to look for a specific element defined between a range of element specified as a parameter.
You can find a real example in the same page.
Container list is not adopted for ordering storing of elements and for their direct access. Though standard class std::list has member functions sort nevertheless the search using bidirectional iterators (std::listhas bidirectional iterators) instead of random access iterators is not very effective..
It would be better if you would use some associative container as for example std::map or std::set (if you need unique elements) or std::multimap or std::multiset (if elements can be duplucated).
if the order of elements is not important then you could use some standard unordered container as std::unordered_map or std::unordered_set

Which order is used to stack or heap variable creation [duplicate]

This question already has an answer here:
How do I erase elements from STL containers?
(1 answer)
Closed 8 years ago.
I've this code:
#include <algorithm>
#include <iostream>
#include <list>
using namespace std;
struct P
{
bool operator()(const int &n) const
{
return n % 3 == 0;
}
};
int main()
{
std::list<int> l({ 5, 2, 6, 1, 13, 9, 19 });
std::cout << l.size();
std::remove_if(l.begin(), l.end(), P());
std::cout << l.size() << std::endl;
return 0;
}
prints out "77". I expected it would have printed out "75", because the operator () of the P struct, returns true when its argument has not remainder of the division by 3. And that's the case for '6' and '9' (two elements out of seven).
Am I missing something ?
thanks.
To quote from http://www.cplusplus.com/reference/algorithm/remove_if/
The function cannot alter the properties of the object containing the range of elements (i.e., it cannot alter the size of an array or a container): The removal is done by replacing the elements for which pred returns true by the next element for which it does not, and signaling the new size of the shortened range by returning an iterator to the element that should be considered its new past-the-end element.
In other words, it rearranges the elements in the given range so that all the non-removed ones are at the beginning, then returns an iterator just past the end of the non-removed part. But it can't delete any elements, because it doesn't know anything about the underlying container.
Is it possible std::remove_if returns the resulting list?
remove/remove_if only reorders a sequence, it doesn't modify it. Iterators have no access to or knowledge of the container from which they come. You need to pass the result to a suitable erase container member:
l.erase(std::remove_if(l.begin(), l.end(), P()), l.end());
Don't forget the second l.end() so that you get the two-iterator overload of erase that erases a whole range. If you forget it, you end up with the one-iterator overload that only erases a single element.