std::max_element for second largest element? - c++

The STL provides std::max_element to find the largest element in an iterable, e.g. like this:
std::vector<float>::const_iterator max =
std::max_element(obj.pt()->begin(), obj.pt()->end());
return std::distance(obj.pt()->begin(), max);
Is there also something to get an iterator for the n-th largest element?
(Note that max_element returns an iterator and this is actually important: Rather than for the value itself, I am looking for the position of the n-th largest element within the iterable.)

max_element() method can be used to get second largest element by passing lambda function which compares the element with the previously found largest element and if it is equal to the largest element then it'll simply skip that element.
auto largest = max_element(vec.begin(), vec.end());
auto secondLargest = max_element(vec.begin(), vec.end(),
[&largest](unsigned long &a, unsigned long &b) {
if (a == *largest) return true;
if (b == *largest) return false;
return a < b;
});

If you are specifically interested in the second-largest element, you can do a simple scan of the array in which most elements require a single comparison:
float second_largest_element(std::vector<float> vec) {
float m2, m1;
/* Check to make sure that vec has at least 2 elements!! */
std::tie(m2, m1) = std::minmax(vec[0], vec[1]);
for (auto it = vec.begin() + 2, limit = vec.end();
it != limit;
++it)
if (*it > m2) std::tie(m2, m1) = std::minmax(*it, m1);
return m2;
}
Getting the index of (or an iterator to) the second largest element is very similar, although std::minmax is less useful. Here's a very sloppy example:
template<typename T>
typename T::iterator second_largest(T& container) {
using iterator = typename T::iterator;
iterator limit = container.end();
iterator it = container.begin();
if (it != limit) {
iterator first = it++;
if (it != limit) {
iterator second = it++;
if (*first < *second) std::swap(first, second);
for (; it != limit; ++it) {
if (*second < *it) {
if (*first < *it) { second = first; first = it; }
else { second = it; }
}
}
return second;
}
return first;
}
return it;
}
You could also consider using std::accumulate to scan the array, although the explicit for loop is not complicated.

As Dyp mentioned in comment, if you are fine to alter the order of elements within your vector you can use std::nth_element as follows. On top if you use find again over vector you will get original position of the nth element from vector. Since nth_element modifies the positions, you have to keep a local copy of it before doing nth_element operation over vector.
2nd largest element:
std::vector<float> orig_vec=obj.pt;
std::nth_element(obj.pt().begin(), obj.pt().begin()+1,
obj.pt().end(), std::greater<float>());
float 2nd= *(obj.pt().begin()+1);
auto it=std::find(orig_vec.begin(), orig_vec.end(), 2nd);
nth largest element:
std::nth_element(obj.pt().begin(), obj.pt().begin()+n-1,
obj.pt().end(), std::greater<float>());
float nth= *(obj.pt().begin()+n-1);
auto it=std::find(orig_vec.begin(), orig_vec.end(), nth)

This is a trivial algorithm to implement in linear time. The naive approach would be to compare the first two values, and select them as the max and second largest values. Then you need to iterate over the other elements comparing each new element with both of them and adjusting your current max and second largest values. For most use cases that is probably more than enough. If you really care about performance (as in you care a lot) you will need to think what values you want to compare to minimize the number of comparisons.
Also note that float (floating point in general) have quirks... you might get funny values if your input contains NaN or infinite values.

It took me a while to find a solution, because I worked with const vector (so I can't use nth_element) and copy would be just wasting (especially, when vector is holding a bigger structures). So I came with this:
// Find 1st max
auto max1 = max_element(vec.begin(), vec.end());
if (max1 != vec.end())
// Use max1
// Find 2nd max. Split the vector into 2 parts, find max and merge results
auto max2Beg = max_element(vec.begin(), max1);
auto max2End = max_element(max1 + 1, vec.end());
auto max2 = max2Beg == max1 ? max2End :
max2End == vec.end() ? max2Beg : max(max2Beg, max2End);
if (max2 != max1 && max2 != vec.end())
// Use max2

Related

Most efficient way to find iterators of 4 maximum values in const vector in C++

I have to find 4 the biggest numbers in a const vector and return their positions. I want this code to have the best time and space complexity. My first idea is to copy this const vector into vector and bubble sort it 4 times. That gives me 4*N but i have to create a vector. Second idea is to put everything from this const vector into priority_queue. That gives me a N*log2(N) time complexity without creating another variables. The maximum of N is around 100.
Is there any other options to do it in the fastest and the least space-consuming way?
EDIT: It doesn't matter which one is the biggest, I just need to return position of this 4 items in the input vector.
O(n) solution
std::vector<int>::iterator max1 = v.begin(), max2 = v.begin(), max3 = v.begin(), max4 = v.begin();
for(std::vector<int>::iterator it = v.begin(); it != v.end(); it++) {
if((*max1) < (*it)) {
max4 = max3;
max3 = max2;
max2 = max1;
max1 = it;
} else if((*max2) < (*it)) {
max4 = max3;
max3 = max2;
max2 = it;
} else if((*max3) < (*it)) {
max4 = max3;
max3 = it;
} else if((*max4) < (*it)) {
max4 = it;
}
}
You can implement this quite easily with an extra vector, and the nth_element algorithm, which is O(n) time:
std::vector<int> const v = ...;
// create a vector of elements with original indexes
std::vector<std::pair<int,int>> res;
// populate the result vector
int k = 0;
for (int i : v)
res.push_back({i,k++});
// find the maximum 4 elements
std::nth_element(res.begin(), res.begin() + 4, res.end(),
[](auto const &a, auto const &b) { return a.first > b.first; });
Here's a demo.
Note that this solution uses O(n) extra space. If N grows large, then this might not be the right approach for finding just 4 largest elements. It's still a good approach if you want the M largest elements, where M grows like N.
Yes, use a heap of size four. Then you iterate through the vector and update the heap accordingly.
Sample code using std heap methods and finding minimum values (from here) follows.
const std::vector<int> input;
const size_t n = 4;
std::vector<int> ret(n);
auto dfirst = ret.begin(), dlast = ret.end();
// initialize heap with infinity distances
std::fill(dfirst, dlast, 100000000000); // do better here
for (auto it = input.begin(); it != input.end(); ++it)
{
if (*it < *dfirst) {
// remove max. value in heap
std::pop_heap(dfirst, dlast); // add comparator as third arg
// max element is now on position "back" and should be popped
// instead we overwrite it directly with the new element
*(dlast-1) = *it;
std::push_heap(dfirst, dlast); // add comparator as third arg
}
}
std::sort_heap(dfirst, dlast); // remove if not needed, or add comparator as third arg
return ret;
Adapt accordingly:
Use a pair of index, value in the heap to keep track of positions which you like to return
Use comparator that compares on value in the pair and establishes a desc. ordering
This is more generic than #Jugal Rawlani's solution if your number n might change/grow in the future. Otherwise his idea wins.
read the 4 first elements into a vector of 4. sort this vector so that minimum of the 4 is in index 0.
loop on remaining items of the const vector, if current value > min, replace it and re-sort the 4 element vector

I need a std function which checks how many elements occur exactly once in vector

Is there any STL function which does this?
For vector:
4 4 5 5 6 7
The expected output should be 2,because of one 6 and 7
Would you be kind to help me count them classic if there is no STL function?
I don't think there is an algorithm for that in STL. You can copy into a multimap or use a map of frequencies as suggested, but it does extra work that's not necessary because your array happens to be sorted. Here is a simple algorithm that counts the number of singular elements i.e. elements that appear only once in a sorted sequence.
int previous = v.front();
int current_count = 0;
int total_singular = 0;
for(auto n : v) {
if(previous == n) // check if same as last iteration
current_count++; // count the elements equal to current value
else {
if(current_count == 1) // count only those that have one copy for total
total_singular++;
previous = n;
current_count = 1; // reset counter, because current changed
}
}
if(current_count == 1) // check the last number
total_singular++;
You could also use count_if with a stateful lambda, but I don't think it'll make the algorithm any simpler.
If performance and memory doesn't matter to you, use std::map (or unordered version) for this task:
size_t count(const std::vector<int>& vec){
std::map<int,unsigned int> occurenceMap;
for (auto i : vec){
occurenceMap[i]++;
}
size_t count = 0U;
for (const auto& pair : occurenceMap){
if (pair.second == 1U){
count++;
}
}
return count;
}
with templates, it can be generalize to any container type and any containee type.
Use std::unique to count the unique entries(ct_u) and then user vector count on the original one (ct_o). Difference ct_o-ct_u would give the answer.
P.S.: this will only work if the identical entries are together in the original vector. If not, you may want to sort the vector first.
Using algorithm:
std::size_t count_unique(const std::vector<int>& v)
{
std::size_t count = 0;
for (auto it = v.begin(); it != v.end(); )
{
auto it2 = std::find_if(it + 1, v.end(), [&](int e) { return e != *it; });
count += (it2 - it == 1);
it = it2;
}
return count;
}
Demo

How to find the minimal missing integer in a list in an STL way

I want to find the minimal missing positive integer in a given list. That is if given a list of positive integers, i.e. larger than 0 with duplicate, how to find from those missing the one that is the smallest.
There is always at least one missing element from the sequence.
For example given
std::vector<int> S={9,2,1,10};
The answer should be 3, because the missing integers are 3,4,5,6,7,8,11,... and the minimum is 3.
I have come up with this:
int min_missing( std::vector<int> & S)
{
int max = std::max_element(S.begin(), S.end());
int min = std::min_element(S.begin(), S.end());
int i = min;
for(; i!=max and std::find(S.begin(), S.end(), i) != S.end() ; ++i);
return i;
}
This is O(nmlogn) in time, but I cannot figure out if there is a more efficient C++ STL way to do this?
This is not an exercise but I am doing a set of problems for self-improvement , and I have found this to be a very interesting problem. I am interested to see how I can improve this.
You could use std::sort, and then use std::adjacent_findwith a custom predicate.
int f(std::vector<int> v)
{
std::sort(v.begin(), v.end());
auto i = std::adjacent_find( v.begin(), v.end(), [](int x, int y)
{
return y != x+1;
} );
if (i != v.end())
{
return *i + 1;
}
}
It is left open what happens when no such element exists, e.g. when the vector is empty.
Find the first missing positive, With O(n) time and constant space
Basiclly, when you read a value a, just swap with the S[a], like 2 should swap with A[2]
class Solution {
public:
/**
* #param A: a vector of integers
* #return: an integer
*/
int firstMissingPositive(vector<int> A) {
// write your code here
int n = A.size();
for(int i=0;i<n;)
{
if(A[i]==i+1)
i++;
else
{
if(A[i]>=1&&A[i]<=n&& A[A[i]-1]!=A[i])
swap(A[i],A[A[i]-1]);
else
i++;
}
}
for(int i=0;i<n;i++)
if(A[i]!=i+1)
return i+1;
return n+1;
}
};
Assuming the data are sorted first:
auto missing_data = std::mismatch(S.cbegin(), S.cend()-1, S.cbegin() + 1,
[](int x, int y) { return (x+1) == y;});
EDIT
As your input data are not sorted, the simplest solution is to sort them first:
std::vector<int> data(S.size());
std::partial_sort_copy (S.cbegin(), S.cend(), data.begin(), data.end());
auto missing_data = std::mismatch (data.cbegin(), data.cend()-1, data.cbegin()+1,
[](int x, int y) { return (x+1) == y;});
you can use algorithm the standard template library c ++ to work in your code.
#include <algorithm> // std::sort
this std::sort in algorithm:
std::vector<int> v={9,2,5,1,3};
std::sort(v.begin(),v.end());
std::cout << v[0];
I hope I understand what you, looking.
You can do this by building a set of integers and adding larger seen in the set, and holding the minimum not seen in as a counter. Once there is a number that is equal to the latter, go through the set removing elements until there is a missing integer.
Please see below for implementation.
template<typename I> typename I::value_type solver(I b, I e)
{
constexpr typename I::value_type maxseen=
std::numeric_limits<typename I::value_type>::max();
std::set<typename I::value_type> seen{maxseen};
typename I::value_type minnotseen(1);
for(I p=b; p!=e;++p)
{
if(*p == minnotseen)
{
while(++minnotseen == *seen.begin())
{
seen.erase(seen.begin());
}
} else if( *p > minnotseen)
{
seen.insert(*p);
}
}
return minnotseen;
}
In case you sequence is in a vector you should use this with:
solver(sequence.begin(),sequence.end());
The algorithm is O(N) in time and O(1) in space since it uses only a counter, constant size additional space, and a few iterators to keep track of the least value.
Complexity ( order of growth rate ) The algorithm keeps a subset only of the input which is expected to be of constant order of growth with respect the growth rate of the input, thus O(1) in space. The growth rate of the iterations is O(N+NlogK) where K is the growth rate of the larger subsequence of seen larger numbers. The latter is the aforementioned subsequence of constant growth rate i.e. K=1 , which results in the algorithm having O(N) complexity. (see comments)

Removing by index from a C++ vector using remove_if

We can use remove_if in C++ to remove elements from a vector in linear time based on a predicate that operates on the elements.
bool condition(double d) {...}
vector<double> data = ...
std::remove_if (data.begin(), data.end(), condition);
What if my condition depends not on the values, but on the indices? In other words, if I wanted to remove all the odd-indexed elements, or some arbitrary index set, etc?
bool condition(int index) {//returns whether this index should be removed}
vector<double> data = ...
std::remove_if (data.begin(), data.end(), ???);
You can use pointer arithmetic to find the index of a specific element that std::remove_if passes to the predicate:
std::remove_if(data.begin(), data.end(),
[&data](const double& d) { return (&d - &*data.begin()) % 2); });
Note that remove_if passes the result of dereferencing an iterator, and that's guaranteed to be a reference per Table 106 - Iterator requirements in the Standard.
I actually made an account only for this. Use awesomeyi answer. Is way cleaner.
int count = 0;
auto final = std::remove_if (data.begin(), data.end(), [&count](const double d) {
return (count++) % 2;
});
The standard does say that the predicate is applied exactly last - first times. And remove_if works with ForwardIterators.
This implies that the predicate is applied only once in the same order they originally appear in the sequence.
Unless of course, the library is trolling you, by keeping internal copies of the ForwardIterator.
Take advantage of the fact that lambas can capture variables. A quick example:
vector<double> data = {5, 3, 6, 7, 8};
int count = 0;
auto final = std::remove_if (data.begin(), data.end(), [&](const double d) {
bool b = false;
if(count % 2) b = true;
++count;
return b;
});
for(auto beg = data.begin(); beg != final; ++beg)
cout << *beg << endl;
Code will print: 5 6 8
An algorithm similar to std::remove_if, but passing indexes to it's predicate
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_indexes_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
ForwardIt dest = first;
for(ForwardIt i = first; i != last; ++i)
if (!p(std::distance(first, i)))
*dest++ = std::move(*i);
return dest;
}

How to navigate through a vector using iterators? (C++)

The goal is to access the "nth" element of a vector of strings instead of the [] operator or the "at" method. From what I understand, iterators can be used to navigate through containers, but I've never used iterators before, and what I'm reading is confusing.
If anyone could give me some information on how to achieve this, I would appreciate it. Thank you.
You need to make use of the begin and end method of the vector class, which return the iterator referring to the first and the last element respectively.
using namespace std;
vector<string> myvector; // a vector of stings.
// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");
vector<string>::iterator it; // declare an iterator to a vector of strings
int n = 3; // nth element to be found.
int i = 0; // counter.
// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ ) {
// found nth element..print and break.
if(i == n) {
cout<< *it << endl; // prints d.
break;
}
}
// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl; // prints d.
// using the at method
cout << myvector.at(n) << endl; // prints d.
In C++-11 you can do:
std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
// access by value, the type of i is int
std::cout << i << ' ';
}
std::cout << '\n';
See here for variations: https://en.cppreference.com/w/cpp/language/range-for
Typically, iterators are used to access elements of a container in linear fashion; however, with "random access iterators", it is possible to access any element in the same fashion as operator[].
To access arbitrary elements in a vector vec, you can use the following:
vec.begin() // 1st
vec.begin()+1 // 2nd
// ...
vec.begin()+(i-1) // ith
// ...
vec.begin()+(vec.size()-1) // last
The following is an example of a typical access pattern (earlier versions of C++):
int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
The advantage of using iterator is that you can apply the same pattern with other containers:
sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
sum += *it;
}
For this reason, it is really easy to create template code that will work the same regardless of the container type.
Another advantage of iterators is that it doesn't assume the data is resident in memory; for example, one could create a forward iterator that can read data from an input stream, or that simply generates data on the fly (e.g. a range or random number generator).
Another option using std::for_each and lambdas:
sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });
Since C++11 you can use auto to avoid specifying a very long, complicated type name of the iterator as seen before (or even more complex):
sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
And, in addition, there is a simpler for-each variant:
sum = 0;
for (auto value : vec) {
sum += value;
}
And finally there is also std::accumulate where you have to be careful whether you are adding integer or floating point numbers.
Vector's iterators are random access iterators which means they look and feel like plain pointers.
You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [].
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];
Alternatively you can use the advance function which works with all kinds of iterators. (You'd have to consider whether you really want to perform "random access" with non-random-access iterators, since that might be an expensive thing to do.)
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
std::advance(it, 5);
int sixth = *it;
Here is an example of accessing the ith index of a std::vector using an std::iterator within a loop which does not require incrementing two iterators.
std::vector<std::string> strs = {"sigma" "alpha", "beta", "rho", "nova"};
int nth = 2;
std::vector<std::string>::iterator it;
for(it = strs.begin(); it != strs.end(); it++) {
int ith = it - strs.begin();
if(ith == nth) {
printf("Iterator within a for-loop: strs[%d] = %s\n", ith, (*it).c_str());
}
}
Without a for-loop
it = strs.begin() + nth;
printf("Iterator without a for-loop: strs[%d] = %s\n", nth, (*it).c_str());
and using at method:
printf("Using at position: strs[%d] = %s\n", nth, strs.at(nth).c_str());