STL algorithm for smallest max element than a given value - c++

Recently I came across this code fragment:
// look for element which is the smallest max element from
// a given iterator
int diff = std::numeric_limits<int>::max();
auto it = nums.rbegin();
auto the_one = nums.rbegin();
for (; it != given; ++it) // this terminates
{
int local_diff = *it - *given;
// if the element is less than/equal to given we are not interested
if (local_diff <= 0)
continue;
if (local_diff < diff)
{
// this update the global diff
diff = local_diff;
the_one = it;
}
}
I was wondering if anyone can think of an elegant stl algorithm to replace the above. Essentially we have to go through all the elements, and also keep track of the one which we need. This is not similar to std::max_element (atleast I can't model it that way).

auto the_one = std::min_element(nums.rbegin(), given,
[given](int a, int b) {
bool good_a = a > *given;
bool good_b = b > *given;
return (good_a && good_b) ? a < b : good_a;
});
The trick is to write a comparison function that declares any "good" element (one that's greater than *given) to compare smaller than any "not good" element. Two "good" elements are compared normally; two "bad" elements are always declared equivalent.

Related

Efficiently get largest 3 integers in C++ Linked List (unsorted)

I heard there were some std functions that do give the largest n integers of an array, but how about a linked list?
I would think a solution would be to have a few for loops to iterate over the linked list, but it seems as if there could be a simpler solution in the C++ libraries.
Thanks.
I would do it like this if you can't use another data structure:
typedef std::list<int> IntList;
InstList list = <your_values>;
int top[3];
for (size_t i = 0; i < 3; i++)
top[i] = std::numeric_limits<int>::min();
IntList::iterator it, end;
for (it = list.begin(), end = list.end(); it != end; ++it) {
const int& value = *it;
if (value > top[2]) {
top[0] = top[1];
top[1] = top[2];
top[2] = value;
} else if (value > top[1]) {
top[0] = top[1];
top[1] = value;
} else if (value > top[0]) {
top[0] = value;
}
}
Perhaps look into using a priority_queue.
The basic idea is to maintain a sorted list, priority queue, or heap of exactly N numbers. You push the first N values of your list into that, then you iterate through the remainder. If you encounter item that is larger than the smallest value in your queue (or whatever), you remove that element and push the new one in.
If you're only looking for N=3, then using a simple array is probably better than a priority queue or anything else. You can determine which element in that array is the minimum with just two comparisons. You always remember the index of the minimum element, and only update that when you replace it.
Interestingly, this approach would have the worst performance for a list that is sorted in ascending order. However, it is still essentially linear time complexity.

Retrieving two highest values from vector

I have declared a vector that stores an area of all Bounding Boxes in a given frame. I then used a iterated this vector from beginning to end to retrieve value. I then sorted these values in ascending order (lowest -> highest).
Here is the Code i use:
double area = contourArea(boundingBoxArea);
list_area.push_back(area);
sort(list_area.begin(), list_area.end());
vector<double>::const_iterator area_iter;
int i = 0;
for(area_iter = list_area.begin(); area_iter != list_area.end(); area_iter++)
{
i++;
cout<<"Iterator " <<i<< " size is : " <<*area_iter<<endl;
}
My issue is that I am only interested in the last two values out of the set of numbers (2 highest values) but I cant really get my head around it to how should i go about it to achieve my goal.
Anyone out here has a suggestion or solution to my problem...?
Regards
Iterate over the list, compare the new value each time against the old highest value. If the new value is higher store it as the highest and have a second variable that that keeps the previous highest value.
Something like this .. may not be syntactically correct but here it is:-
int iCurrentHighest = 0;
int previousHighest = 0;
for(area_iter = list_area.begin(); area_iter != list_area.end(); area_iter++)
{
if(*area_iter>iCurrentHighest)
{
previousHighest = iCurrentHighest;
iCurrentHighest = *area_iter;
}
else
{
if ((*area_iter<iCurrentHighest) && (*area_iter>previousHighest))
{
previousHighest = *area_iter;
}
}
}
What you need is std::nth_element
double area = contourArea(boundingBoxArea);
list_area.push_back(area);
std::nth_element(list_area.begin(), list_area.begin() + 2, list_area.end(), std::greater<double>());
// first 2 elements in list_area are now 2 greatest
vector<double>::const_iterator area_iter;
int i = 0;
for(area_iter = list_area.begin(); area_iter != list_area.end(); area_iter++)
{
i++;
cout<<"Iterator " <<i<< " size is : " <<*area_iter<<endl;
}
This is a different version of the algorithm provided by #Rich above with slightly less comparisons (instead of testing each value with the largest and then the second largest, by reversing the order the expected number of comparisons can be reduced: if a number is smaller than the second largest it gets compared only once).
int first = 0;
int second = 0;
for (auto const & v : list) {
if (v > second) {
second = v;
if (second > first)
std::swap(first,second);
}
}
If there is no known value that is less than all others, the first and second values can be initialized with the first two values in the vector (in order).

Extracting lowest complex number from a vector

The vector is taking points to a rectangle. I want to be able to take the lowest and highest complex number and assigne it to 2 different complex numbers. I've only tried for the lowest with the below but it doesnt seem to find the lowest and just return the 1st element.
vector < complex<double>* > xs;
typedef typename vector < complex<double>* >::iterator Iter;
xs.push_back(&pointa);
xs.push_back(&pointb);
xs.push_back(&pointc);
xs.push_back(&pointd);
for (Iter p = xs.begin(); p != xs.end(); ++p)
{
if((*p)->real()<(*p+1)->real() && (*p)->imag()<(*p+1)->imag())
{
double a = (*p)->real();
double b = (*p)->imag();
complex <double> botleft_1(a,b);
}
else
{
}
}
Any suggestions?
The immediate bug in your code is that *p+1 means (*p)+1.
The next bug after you fix that to *(p+1) will be that you go one element off the end of the vector. You should be comparing each value with the lowest/highest so far, not with the next value in the vector.
There is in any case no such thing as the "lowest" or "highest" complex number - the complex numbers are not an ordered field (theorem). You can define any comparison operator you like on complex numbers, but it will be pretty arbitrary, for example it won't necessarily have ordered field properties such as a < b && c < d => a+c < b+d. The comparison you have defined does have that property, but is not a strict weak order, so it might not behave the way you expect once you start doing comparisons among 3 or more values.
For example, consider the values complex<double> a(1,1), b(0,3), c(2,2);, and the comparison function lt(complex<double> lhs, complex<double> rhs) { return lhs.real() < rhs.real() && lhs.imag() < rhs.imag(); }.
Then lt(a,b) and lt(b,a) are both false. This means a and b are equivalent as far as the ordering is concerned.
Likewise, lt(b,c) and lt(c,b) are both false. This means b and c are equivalent as far as the ordering is concerned.
However, lt(a,c) is true. This means a and c are not equivalent as far as the ordering is concerned.
In the loop you do not compare with the lowest number, only with next number. Try something like this:
complex<double> *lowest = *xs.begin();
for (Iter p = xs.begin() + 1; p != xs.end(); ++p){
if ((*p)->real() < lowest->real() && (*p)->imag() < lowest->imag())
lowest = *p;
}
After the loop, the variable lowest will have be the one you want.
Also, in your version of the loop, you compare to p + 1 which will be xs.end() on the last item, and that will not be a valid pointer.
Use boost::minmax_element
std::pair< Iter > pairit = boost::minmax_element( xs.begin(), xs.end(),
[&]( complex<double>* pcomplexA, complex<double>* pcomplexB ) {
// Suitable comparison predicate (see Steve Jessop's answer)
return pcomplexA->abs() < pcomplexB->abs(); // |a| < |b|
});

Find largest and second largest element in a range

How do I find the above without removing the largest element and searching again? Is there a more efficient way to do this? It does not matter if the these elements are duplicates.
for (e: all elements) {
if (e > largest) {
second = largest;
largest = e;
} else if (e > second) {
second = e;
}
}
You could either initialize largest and second to an appropriate lower bound, or to the first two items in the list (check which one is bigger, and don't forget to check if the list has at least two items)
using partial_sort ?
std::partial_sort(aTest.begin(), aTest.begin() + 2, aTest.end(), Functor);
An Example:
std::vector<int> aTest;
aTest.push_back(3);
aTest.push_back(2);
aTest.push_back(4);
aTest.push_back(1);
std::partial_sort(aTest.begin(), aTest.begin()+2,aTest.end(), std::greater<int>());
int Max = aTest[0];
int SecMax = aTest[1];
nth_element(begin, begin+n,end,Compare) places the element that would be nth (where "first" is "0th") if the range [begin, end) were sorted at position begin+n and makes sure that everything from [begin,begin+n) would appear before the nth element in the sorted list. So the code you want is:
nth_element(container.begin(),
container.begin()+1,
container.end(),
appropriateCompare);
This will work well in your case, since you're only looking for the two largest. Assuming your appropriateCompare sorts things from largest to smallest, the second largest element with be at position 1 and the largest will be at position 0.
Lets assume you mean to find the two largest unique values in the list.
If the list is already sorted, then just look at the second last element (or rather, iterate from the end looking for the second last value).
If the list is unsorted, then don't bother to sort it. Sorting is at best O(n lg n). Simple linear iteration is O(n), so just loop over the elements keeping track:
v::value_type second_best = 0, best = 0;
for(v::const_iterator i=v.begin(); i!=v.end(); ++i)
if(*i > best) {
second_best = best;
best = *i;
} else if(*i > second_best) {
second_best = *i;
}
There are of course other criteria, and these could all be put into the test inside the loop. However, should you mean that two elements that both have the same largest value should be found, you have to consider what happens should three or more elements all have this largest value, or if two or more elements have the second largest.
The optimal algorithm shouldn't need more than 1.5 * N - 2 comparisons. (Once we've decided that it's O(n), what's the coefficient in front of N? 2 * N comparisons is less than optimal).
So, first determine the "winner" and the "loser" in each pair - that's 0.5 * N comparisons.
Then determine the largest element by comparing winners - that's another 0.5 * N - 1 comparisons.
Then determine the second-largest element by comparing the loser of the pair where the largest element came from against the winners of all other pairs - another 0.5 * N - 1 comparisons.
Total comparisons = 1.5 N - 2.
The answer depends if you just want the values, or also iterators pointing at the values.
Minor modification of #will answer.
v::value_type second_best = 0, best = 0;
for(v::const_iterator i=v.begin(); i!=v.end(); ++i)
{
if(*i > best)
{
second_best = best;
best = *i;
}
else if (*i > second_best)
{
second_best = *i;
}
}
Create a sublist from n..m, sort it descending. Then grab the first two elements. Delete these elements from the orginal list.
You can scan the list in one pass and save the 1st and 2nd values, that has a O(n) efficiency while sorting is O(n log n).
EDIT:
I think that partial sort is O(n log k)
Untested but fun:
template <typename T, int n>
class top_n_functor : public unary_function<T, void>
{
void operator() (const T& x) {
auto f = lower_bound(values_.begin(), values_.end(), x);
if(values_.size() < n) {
values_.insert(f, x);
return;
}
if(values_.begin() == f)
return;
auto removed = values_.begin();
values_.splice(removed, values_, removed+1, f);
*removed = x;
}
std::list<T> values() {
return values_;
}
private:
std::list<T> values_;
};
int main()
{
int A[] = {1, 4, 2, 8, 5, 7};
const int N = sizeof(A) / sizeof(int);
auto vals = for_each(A, A + N, top_n_functor<int,2>()).values();
cout << "The top is " << vals.front()
<< " with second place being " << *(vals.begin()+1) << endl;
}
If the largest is the first element, search for the second largest in [largest+1,end). Otherwise search in [begin,largest) and [largest+1,end) and take the maximum of the two. Of course, this has O(2n), so it's not optimal.
If you have random-access iterators, you could do as quick sort does and use the ever-elegant recursion:
template< typename T >
std::pair<T,T> find_two_largest(const std::pair<T,T>& lhs, const std::pair<T,T>& rhs)
{
// implementation finding the two largest of the four values left as an exercise :)
}
template< typename RAIter >
std::pair< typename std::iterator_traits<RAIter>::value_type
, typename std::iterator_traits<RAIter>::value_type >
find_two_largest(RAIter begin, RAIter end)
{
const ptr_diff_t diff = end-begin;
if( diff < 2 )
return std::make_pair(*begin, *begin);
if( diff < 3 )
return std::make_pair(*begin, *begin+1);
const RAIter middle = begin + (diff)/2;
typedef std::pair< typename std::iterator_traits<RAIter>::value_type
, typename std::iterator_traits<RAIter>::value_type >
result_t;
const result_t left = find_two_largest(begin,middle);
const result_t right = find_two_largest(middle,end);
return find_two_largest(left,right);
}
This has O(n) and shouldn't make more comparisons than NomeN's implementation.
top k is usually a bit better than n(log k)
template <class t,class ordering>
class TopK {
public:
typedef std::multiset<t,ordering,special_allocator> BEST_t;
BEST_t best;
const size_t K;
TopK(const size_t k)
: K(k){
}
const BEST_t& insert(const t& item){
if(best.size()<k){
best.insert(item);
return best;
}
//k items in multiset now
//and here is why its better - because if the distribution is random then
//this and comparison above are usually the comparisons that is done;
if(compare(*best.begin(),item){//item better than worst
erase(begin());//the worst
best.insert(item); //log k-1 average as only k-1 items in best
}
return best;
}
template <class it>
const BEST_t& insert(it i,const it last){
for(;i!=last;++i){
insert(*i);
}
return best;
}
};
Of course the special_allocator can in essence be just an array of k multiset value_types and a list of those nodes (which typically has nothing on it as the other k are in use in the multiset until its time to put a new one in and we erase and then immediate ly reuse it. Good to have this or else the memory alloc/free in std::multiset and the cache line crap kills ya. Its a (very) tiny bit of work to give it static state without violating STL allocator rules.
Not as good as a specialized algo for exactly 2 but for fixed k<<n, I would GUESS (2n+delta*n) where delta is small - my DEK ACP vol3 S&S is packed away and an estimate on delta is a bit more work that I want to do.
average worst is I would guess n(log(k-1) + 2) when in opposite order and all distinct.
best is 2n + k(log k) for the k best being the first
I think you could implement a custom array and overload the indexed get/set methods of elements. Then on every set call, compare the new value with two fields for the result. While this makes setter slower, it benefits from caching or even registers. Then its a no op to get the result. This must be faster if you populate array only once per finding maximums. But if array is modified frequently, then it is slower.
If array is used in vectorized loops, then it gets harder to implement as you have to use avx/sse optimized max methods inside setter.

Finding gaps in sequence of numbers

I have a std::vector containing a handful of numbers, which are not in any particular order, and may or may not have gaps between the numbers - for example, I may have { 1,2,3, 6 } or { 2,8,4,6 } or { 1, 9, 5, 2 }, etc.
I'd like a simple way to look at this vector and say 'give me the lowest number >= 1 which does not appear in the vector'. So,
for the three examples above, the answers would be 4, 1 and 3 respectively.
It's not performance critical, and the list is short so there aren't any issues about copying the list and sorting it, for example.
I am not really stuck for a way to do this, but my STL skills are seriously atrophied and I can feel that I'm about to do something inelegant - I would be interested to see what other people came up with.
The standard algorithm you are looking for is std::adjacent_find.
Here is a solution that also uses a lambda to make the predicate clean:
int first_gap( std::vector<int> vec )
{
// Handle the special case of an empty vector. Return 1.
if( vec.empty() )
return 1;
// Sort the vector
std::sort( vec.begin(), vec.end() );
// Find the first adjacent pair that differ by more than 1.
auto i = std::adjacent_find( vec.begin(), vec.end(), [](int l, int r){return l+1<r;} );
// Handle the special case of no gaps. Return the last value + 1.
if ( i == vec.end() )
--i;
return 1 + *i;
}
The checked answer uses < for comparison. != is much simpler:
int find_gap(std::vector<int> vec) {
std::sort(vec.begin(), vec.end());
int next = 1;
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
if (*it != next) return next;
++next;
}
return next;
}
find_gap(1,2,4,5) = 3
find_gap(2) = 1
find_gap(1,2,3) = 4
I'm not passing a reference to the vector since a) he said time doesn't matter and b) so I don't change the order of the original vector.
Sorting the list and then doing a linear search seems the simplest solution. Depending on the expected composition of the lists you could use a less general purpose sorting algorithm, and if you implement the sort yourself you could keep track of data during the sort that could be used to speed up (or eliminate entirely) the search step. I do not think there is any particularly elegant solution to this problem
You could allocate a bit vector (of the same length as the input vector), initialize it to zero, then mark all indices that occur (note that numbers larger than the length can be ignored). Then, return the first unmarked index (or the length if all indices are marked, which only happens if all indices occur exactly once in the input vector).
This should be asymptotically faster than sort and search. It will use more memory than sorting if you are allowed to destroy the original, but less memory than sorting if you must preserve the original.
Actually, if you do a bubble sort (you know... the one that they teach you first and then tell you to never use again...), you will be able to spot the first gap early in the sorting process, so you can stop there. That should give you the fastest overall time.
Sort-n-search:
std::sort(vec.begin(), vec.end());
int lowest = 1;
for(size_t ii = 1; ii < vec.size(); ++ii)
{
if (vec[ii - 1] + 1 < vec[ii])
{
lowest = (vec[ii - 1] + 1);
break;
}
}
/* 1, 2, ..., N case */
if (lowest == vec[0]) lowest = (*vec.back()) + 1;
Iterators could be used with just as clear intent as showcased in #joe_mucchiello's (ed: better) answer.
OK, here's my 2 cents. Assume you've got a vector of length N.
If N<=2 you can check directly
First, use min_element to get the smallest element, remember it as emin
Call nth_element to get the element at N/2, call it ehalf
If ehalf != emin+N/2 there's a gap to the left, apply this method recursively there by calling nth_element on the whole array but asking for element N/4. Otherwise, recurse on the right asking for element 3*N/4.
This should be slightly better than sorting completely up front.
you could go with something like....
struct InSequence
{
int _current; bool insequence;
InSequence() : _current(1), insequence(true){}
bool operator()(int x) {
insequence = insequence ? (x == _current) : false;
_current++;
return insequence;
}
};
int first_not_in_sequence(std::vector<int>& v)
{
std::sort(v.begin(), v.end());
return 1+std::count_if(v.begin(), v.end(),InSequence());
}
A possible implementation of Thomas Kammeyer's answer
I found Thomas' approach really smart and useful - since some of us dream in code and I find the actual implementation a bit tricky I wanted to provide some ready-to-use code.
The solution presented here is as generic as possible:
No assumption is made on the type of container or range except their iterators must meet the requirements of ValueSwappable and RandomAccessIterator (due to partial sorting with nth_element)
Any number type can be used - the required traits are outlined below
Another improvement I think is that a no-gap condition can be checked early: since we have to scan for the minimum anyway we can also scan for the maximum at the same time and then determine whether the number range even contains a gap worth finding.
Last but not least the same recursive approach can be adapted for sorted ranges! If you encode in a template value parameter whether the range is already sorted, you can simply skip the partial sorting plus make determining minimum/maximum elements a no-op.
#include <type_traits>
#include <iterator>
#include <tuple>
#include <utility>
#include <algorithm>
#include <cstddef>
// number type must be:
// * arithmetic
// * subtractable (a - b)
// * divisible by 2 (a / 2)
// * incrementable (++a)
// * less-than-comparable (a < b)
// * default-constructible (A{})
// * copy-constructible
// * value-constructible (A(n))
// * unsigned or number range must only contain values >0
/** Find lowest gap value in a range */
template<typename Range>
typename std::remove_reference_t<Range>::value_type
lowest_gap_value_unsorted(Range&& r)
{
static_assert(!std::is_lvalue_reference_v<Range> && !std::is_const_v<Range>, "lowest_gap_value_unsorted requires a modifiable copy of the passed range");
return lowest_gap_value_unsorted(std::begin(r), std::end(r), std::size(r));
}
/** Find lowest gap value in a range with specified size */
template<typename Range>
typename std::remove_reference_t<Range>::value_type
lowest_gap_value_unsorted(Range&& r, std::size_t N)
{
static_assert(!std::is_lvalue_reference_v<Range> && !std::is_const_v<Range>, "lowest_gap_value_unsorted requires a modifiable copy of the passed range");
return lowest_gap_value_unsorted(std::begin(r), std::end(r), N);
}
/** Find lowest gap value in an iterator range */
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
lowest_gap_value_unsorted(Iterator first, Iterator last)
{
return lowest_gap_value_unsorted(first, last, std::distance(first, last));
}
/** Find lowest gap value in an iterator range with specified size */
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
lowest_gap_value(Iterator first, Iterator last, std::size_t N)
{
typedef typename std::iterator_traits<Iterator>::value_type Number;
if (bool empty = last == first)
return increment(Number{});
Iterator minElem, maxElem;
std::tie(minElem, maxElem) = std::minmax_element(first, last);
if (bool contains0 = !(Number{} < *minElem))
throw std::logic_error("Number range must not contain 0");
if (bool missing1st = increment(Number{}) < *minElem)
return increment(Number{});
if (bool containsNoGap = !(Number(N) < increment(*maxElem - *minElem)))
return increment(*maxElem);
return lowest_gap_value_unsorted_recursive(first, last, N, *minElem);
}
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
lowest_gap_value_unsorted_recursive(Iterator first, Iterator last, std::size_t N, typename std::iterator_traits<Iterator>::value_type minValue)
{
typedef typename std::iterator_traits<Iterator>::value_type Number;
if (N == 1)
return ++minValue;
if (N == 2)
{
// determine greater of the 2 remaining elements
Number maxValue = !(minValue < *first) ? *std::next(first) : *first;
if (bool gap = ++minValue < maxValue)
return minValue;
else
return ++maxValue;
}
Iterator medianElem = std::next(first, N / 2);
// sort partially
std::nth_element(first, medianElem, last);
if (bool gapInLowerHalf = (Number(N) / 2 < *medianElem - minValue))
return lowest_gap_value_unsorted_recursive(first, medianElem, N / 2, minValue);
else
return lowest_gap_value_unsorted_recursive(medianElem, last, N / 2 + N % 2, *medianElem);
};
template<typename T>
T increment(T v)
{
return ++v;
}