Find biggest value in vector of tuples - c++

I have a vector of tuples.
Pseudo:
vector<(x, x)>
Where the two x'es represent two different values. What I want to do is find the x with the biggest value in the whole vector.
Code:
#include <iostream>
#include <vector>
#include <tuple>
int main() {
//Making vector
std::vector<std::tuple<int, int>> v;
//Adding one random tuple to it
v.push_back(std::make_tuple(1,50));
//Getting biggest value in the vector
int bufferMax = 0;
for (auto i : v) {
for (int j = 0; j < 2; j++) {
int nrToTest = std::get<0>(i);
if (j == 1) std::get<1>(i);
if (nrToTest > bufferMax) bufferMax = nrToTest;
}
}
//Output biggest
std::cout << bufferMax << std::endl;
}
Output: 1
In the first loop I loop over all tuples in the vector, than I have a second loop oscillating between the values 0 and 1. If that value is 0 I compare the first element in tuple i with the buffer, otherwise the second element in tuple i.
However, this code doesn't work as you can see at the output.
Why doesn't this algorithm work?
I have found another algorithm which does work (I guess)
int bufferMax = 0;
for (auto i : v) {
//Biggest tuple value:
int nrToTest = std::get<0>(i);
if (std::get<0>(i) < std::get<1>(i)) {
nrToTest = std::get<1>(i);
}
if (nrToTest > bufferMax) bufferMax = nrToTest;
}
But I am still wondering why the first one doesn't work?

It depends on how you define the max value. In the first code snippet, you compare only the first value of each tuple:
int bufferMax = 0;
for (auto i : v) { // Iterate over all elements
for (int j = 0; j < 2; j++) {
int nrToTest = std::get<0>(i); // Get the first entry in the tuple
if (j == 1) std::get<1>(i); // This is useless: you get the second value
// in the tuple but you don't do anything with it.
if (nrToTest > bufferMax) // You update the max, but nrToTest
// is always the first value in the tuple
bufferMax = nrToTest;
}
}
The second snippet works because, at each iteration, you set the nrToTest to be the largest of the entries in the tuple, and then you compare it with the global maximum.

This code snippet ( sorting by first element) works:
std::vector<tuple<int, int>> vec;
The sorting using std::max_element
auto result = std::max_element(vec.begin(), vec.end(), [](const std::tuple<int, int>& lhs, const std::tuple<int, int>& rhs)
{
return std::get<0>(lhs) < std::get<0>(rhs);
});
Use std::tie to obtain the result:
int a, b;
std::tie(a,b) = *(result);
std::cout << a << " " << b << std::endl;

Related

Removing non-prime numbers from a vector

I have a simple function that "primes a list" i.e. it returns the passed vector but without all non-primes. Essentially it removes non-primes from the vector and returns the updated vector. But my function just returns the vector without the numbers 0 and 1. Assume the vector is sorted in ascending order(0, 1, 2, 3, ... ) The basic structure of my function follows:
#include<vector>
#include<algorithms>
#include "cmath.h"
.
.
.
std::vector<int> prime_list(std::vector<int> foo){
int limit_counter = 1;
const int p_limit = sqrt(foo.at(foo.size() - 1));
for(int w = 0; w < foo.size(); w++){
if(foo.at(w) <= 1)
foo.erase(foo.begin() + w);
}
for(int i : foo){
do{
if(i % limit_counter == 0)
foo.erase(std::remove(foo.begin(), foo.end(), i), foo.end());
limit_counter++;
}
while(limit_counter < p_limit);
}
return foo;
}
const int p_limit = sqrt(foo.at(foo.size() - 1));
This will initialize the limit once, based on the last element in the list. You have to do that for each element being test for prime.
More importantly, limit_counter should be initialized for each i
Ignoring the problem with iterators, you can fix it with this pseudo code.
std::vector<int> prime_list(std::vector<int> foo)
{
foo.erase(std::remove(foo.begin(), foo.end(), 0), foo.end());
foo.erase(std::remove(foo.begin(), foo.end(), 1), foo.end());
for (int i : foo)
{
int limit_counter = 1;
const int p_limit = static_cast<int>(sqrt(i));
do
{
if (i % limit_counter == 0)
{
//undefined behavior, this might destroy the iterator for `i`
foo.erase(std::remove(foo.begin(), foo.end(), i), foo.end());
}
limit_counter++;
} while (limit_counter < p_limit);
}
return foo;
}
For an easier and safer solution, just create a new list and add the primes to it. Or, create a duplicate list primes and go through the loop in foo
std::vector<int> prime_list(std::vector<int> &foo)
{
std::vector<int> primes = foo;
primes.erase(std::remove(primes.begin(), primes.end(), 0), primes.end());
primes.erase(std::remove(primes.begin(), primes.end(), 1), primes.end());
for (int n : foo)
for (int k = 2, limit = static_cast<int>(sqrt(n)); k <= limit; k++)
if (n % k == 0)
primes.erase(std::remove(primes.begin(), primes.end(), n), primes.end());
return primes;
}
There are basically 2 possible solutions.
You can either erase none prime values from the std::vector
or copy just prime values to a new std::vector
For both solutions it is necessary to have a function, which detects, if a number is a prime or not. There are tons of such functions in the internet. Please select the best for your requirements.
Then, you need to think, if the erase/remove_if or the copy_if solution is better for you.
With erase/remove_if you are shifting a lot of memory, so, if you use it, then maybe better to start from the end.
On the other hand, copy_if may also invoke memory reallocation and copying, because of push_back and back_inserter actions.
So, sorry to say, it depends . . .
Please see below an example with both solutions.
#include <iostream>
#include <vector>
#include <algorithm>
// Some of the many isPrime functions, available in the internet
// Basically, for this example, it does not matter which
bool isPrime(int number){
if(number < 2) return false;
if(number % 2 == 0) return false;
for(int i=3; (i*i)<=number; i+=2)
if(number % i == 0 ) return false;
return true;
}
// Version with erase/remove idiom
// Yes, no reference for input parameter. Data shall be copied
auto primeVector1(std::vector<int> data) {
// Remove all none primes
data.erase(std::remove_if(data.begin(), data.end(), [](const int i){ return not isPrime(i);}),data.end());
return data;
}
// Version with copying prime data to new vector
auto primeVector2(std::vector<int>& data) {
std::vector<int> result{};
// Copy primes to new vector
std::copy_if(data.begin(), data.end(), std::back_inserter(result), [](const int i){ return isPrime(i);});
return result;
}
// Test/Driver code
int main() {
std::vector test{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
for (const int i : primeVector1(test)) std::cout << i << ' '; std::cout << '\n';
for (const int i : primeVector2(test)) std::cout << i << ' '; std::cout << '\n';
}

give how many numbers in a vector that are less than itself

i have to find how many other numbers are less than nums[i] and return them in another vector, for example [6,5,4,8] nums[0] = 6 so there is two numbers less than 6. so 2 would be pushed to the other vector. i am not getting 3 when it comes to checking the last element
class Solution {
public:
vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
vector<int> nums2;
for(int i =0; i< nums.size(); ++i){
int max = nums[i];
int count = 0;
for(int j =0; j < nums.size(); ++j){
if(nums[j] < max && j!=0)
count++;
else
continue;
}
nums2.push_back(count);
}
return nums2;
}
};
You exclude the first element when counting in the condition:
if(nums[j] < max && j!=0)
// ^^ ---- remove this
There are algorithms that do want you need. std::transform transforms one range of values to another one and count_if counts how often a predicate returns true for a given range:
#include <vector>
#include <iostream>
#include <algorithm>
std::vector<size_t> count_if_smaller(const std::vector<int>& v) {
std::vector<size_t> result(v.size());
std::transform(v.begin(),v.end(),result.begin(),
[&](int x){
return std::count_if(v.begin(),v.end(),[&](int y){
return y < x;
});
} );
return result;
}
int main() {
std::vector<int> v{6,5,4,8};
auto r = count_if_smaller(v);
for (auto e : r) std::cout << e << " ";
}
One advantage of using algorithms is that you need not bother about indices of single elements. Introducing the same bug as in your code would be more difficult in the above. In other words, using algorithms is less error prone. Consider to use them when you can.
PS: Your current approach has complexity O(N^2). If you sort the input vector you could get O(N log N) easily.

Assign the index of an element in a vector instead of its value

I'm trying to find the position of an element in a vector and then assigning it to a variable but for some reason its not working.
Here I am using vector.at() as was used by someone doing the same thing here on this site. However when I use it in my case all its returning is the actual element itself instead of the position.
Here is my loop. It is designed to loop though the vector to find the highest value and assign it to a variable(this woks) max and its position to a variable pos but this does not work.
for (int i = 0; i <= people.size(); ++i) {
if (people[i] > max) {
max = people[i];
pos = people.at(i);
}
}
people is my < int > vector.
Your loop goes out of bounds on the last iteration:
for (int i = 0; i <= people.size(); ++i)
^^
It should be:
for (int i = 0; i < people.size(); ++i)
Second, i is the position of the largest element, not people.at(i).
Last, std::max_element does all of this work for you already:
http://en.cppreference.com/w/cpp/algorithm/max_element
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> people = {5, 6,12, 3, 5, 9};
auto it = std::max_element(people.begin(), people.end());
std::cout << "largest element is " << *it << " at people[" << std::distance(people.begin(), it)
<< "]";
}
Output:
largest element is 12 at people[2]
Live example: http://ideone.com/fp0T7i

Finding local extremum in vector of numbers [duplicate]

How can I get the maximum or minimum value in a vector in C++?
And am I wrong in assuming it would be more or less the same with an array?
I need an iterator, right? I tried it with max_element, but I kept getting an error.
vector<int>::const_iterator it;
it = max_element(cloud.begin(), cloud.end());
error: request for member ‘begin’ in ‘cloud’, which is of non-class type ‘int [10]’
Using C++11/C++0x compile flags, you can
auto it = max_element(std::begin(cloud), std::end(cloud)); // C++11
Otherwise, write your own:
template <typename T, size_t N> const T* mybegin(const T (&a)[N]) { return a; }
template <typename T, size_t N> const T* myend (const T (&a)[N]) { return a+N; }
See it live at http://ideone.com/aDkhW:
#include <iostream>
#include <algorithm>
template <typename T, size_t N> const T* mybegin(const T (&a)[N]) { return a; }
template <typename T, size_t N> const T* myend (const T (&a)[N]) { return a+N; }
int main()
{
const int cloud[] = { 1,2,3,4,-7,999,5,6 };
std::cout << *std::max_element(mybegin(cloud), myend(cloud)) << '\n';
std::cout << *std::min_element(mybegin(cloud), myend(cloud)) << '\n';
}
Oh, and use std::minmax_element(...) if you need both at once :/
If you want to use the function std::max_element(), the way you have to do it is:
double max = *max_element(vector.begin(), vector.end());
cout<<"Max value: "<<max<<endl;
Let,
#include <vector>
vector<int> v {1, 2, 3, -1, -2, -3};
If the vector is sorted in ascending or descending order then you can find it with complexity O(1).
For a vector of ascending order the first element is the smallest element, you can get it by v[0] (0 based indexing) and last element is the largest element, you can get it by v[sizeOfVector-1].
If the vector is sorted in descending order then the last element is the smallest element,you can get it by v[sizeOfVector-1] and first element is the largest element, you can get it by v[0].
If the vector is not sorted then you have to iterate over the vector to get the smallest/largest element.In this case time complexity is O(n), here n is the size of vector.
int smallest_element = v[0]; //let, first element is the smallest one
int largest_element = v[0]; //also let, first element is the biggest one
for(int i = 1; i < v.size(); i++) //start iterating from the second element
{
if(v[i] < smallest_element)
{
smallest_element = v[i];
}
if(v[i] > largest_element)
{
largest_element = v[i];
}
}
You can use iterator,
for (vector<int>:: iterator it = v.begin(); it != v.end(); it++)
{
if(*it < smallest_element) //used *it (with asterisk), because it's an iterator
{
smallest_element = *it;
}
if(*it > largest_element)
{
largest_element = *it;
}
}
You can calculate it in input section (when you have to find smallest or largest element from a given vector)
int smallest_element, largest_element, value;
vector <int> v;
int n;//n is the number of elements to enter
cin >> n;
for(int i = 0;i<n;i++)
{
cin>>value;
if(i==0)
{
smallest_element= value; //smallest_element=v[0];
largest_element= value; //also, largest_element = v[0]
}
if(value<smallest_element and i>0)
{
smallest_element = value;
}
if(value>largest_element and i>0)
{
largest_element = value;
}
v.push_back(value);
}
Also you can get smallest/largest element by built in functions
#include<algorithm>
int smallest_element = *min_element(v.begin(),v.end());
int largest_element = *max_element(v.begin(),v.end());
You can get smallest/largest element of any range by using this functions. such as,
vector<int> v {1,2,3,-1,-2,-3};
cout << *min_element(v.begin(), v.begin() + 3); //this will print 1,smallest element of first three elements
cout << *max_element(v.begin(), v.begin() + 3); //largest element of first three elements
cout << *min_element(v.begin() + 2, v.begin() + 5); // -2, smallest element between third and fifth element (inclusive)
cout << *max_element(v.begin() + 2, v.begin()+5); //largest element between third and first element (inclusive)
I have used asterisk (*), before min_element()/max_element() functions. Because both of them return iterator. All codes are in c++.
You can print it directly using the max_element or min_element function.
For example:
cout << *max_element(v.begin(), v.end());
cout << *min_element(v.begin(), v.end());
Assuming cloud is int cloud[10] you can do it like this:
int *p = max_element(cloud, cloud + 10);
In C++11, you can use some function like that:
int maxAt(std::vector<int>& vector_name) {
int max = INT_MIN;
for (auto val : vector_name) {
if (max < val) max = val;
}
return max;
}
If you want to use an iterator, you can do a placement-new with an array.
std::array<int, 10> icloud = new (cloud) std::array<int,10>;
Note the lack of a () at the end, that is important. This creates an array class that uses that memory as its storage, and has STL features like iterators.
(This is C++ TR1/C++11 by the way)
You can use max_element to get the maximum value in vector.
The max_element returns an iterator to largest value in the range, or last if the range is empty. As an iterator is like pointers (or you can say pointer is a form of iterator), you can use a * before it to get the value.
So as per the problem you can get the maximum element in an vector as:
int max=*max_element(cloud.begin(), cloud.end());
It will give you the maximum element in your vector "cloud".
Hope it helps.
Answer on the behalf of the author
for (unsigned int i = 0; i < cdf.size(); i++)
if (cdf[i] < cdfMin)
cdfMin = cdf[i];
where cdf is a vector.
Just this:
// assuming "cloud" is:
// int cloud[10];
// or any other fixed size
#define countof(x) (sizeof(x)/sizeof((x)[0]))
int* pMax = std::max_element(cloud, cloud + countof(cloud));

indices of the k largest elements in an unsorted length n array

I need to find the indices of the k largest elements of an unsorted, length n, array/vector in C++, with k < n. I have seen how to use nth_element() to find the k-th statistic, but I'm not sure if using this is the right choice for my problem as it seems like I would need to make k calls to nth_statistic, which I guess it would have complexity O(kn), which may be as good as it can get? Or is there a way to do this just in O(n)?
Implementing it without nth_element() seems like I will have to iterate over the whole array once, populating a list of indices of the largest elements at each step.
Is there anything in the standard C++ library that makes this a one-liner or any clever way to implement this myself in just a couple lines? In my particular case, k = 3, and n = 6, so efficiency isn't a huge concern, but it would be nice to find a clean and efficient way to do this for arbitrary k and n.
It looks like Mark the top N elements of an unsorted array is probably the closest posting I can find on SO, the postings there are in Python and PHP.
This should be an improved version of #hazelnusse which is executed in O(nlogk) instead of O(nlogn)
#include <queue>
#include <iostream>
#include <vector>
// maxindices.cc
// compile with:
// g++ -std=c++11 maxindices.cc -o maxindices
int main()
{
std::vector<double> test = {2, 8, 7, 5, 9, 3, 6, 1, 10, 4};
std::priority_queue< std::pair<double, int>, std::vector< std::pair<double, int> >, std::greater <std::pair<double, int> > > q;
int k = 5; // number of indices we need
for (int i = 0; i < test.size(); ++i) {
if(q.size()<k)
q.push(std::pair<double, int>(test[i], i));
else if(q.top().first < test[i]){
q.pop();
q.push(std::pair<double, int>(test[i], i));
}
}
k = q.size();
std::vector<int> res(k);
for (int i = 0; i < k; ++i) {
res[k - i - 1] = q.top().second;
q.pop();
}
for (int i = 0; i < k; ++i) {
std::cout<< res[i] <<std::endl;
}
}
8
4
1
2
6
Here is my implementation that does what I want and I think is reasonably efficient:
#include <queue>
#include <vector>
// maxindices.cc
// compile with:
// g++ -std=c++11 maxindices.cc -o maxindices
int main()
{
std::vector<double> test = {0.2, 1.0, 0.01, 3.0, 0.002, -1.0, -20};
std::priority_queue<std::pair<double, int>> q;
for (int i = 0; i < test.size(); ++i) {
q.push(std::pair<double, int>(test[i], i));
}
int k = 3; // number of indices we need
for (int i = 0; i < k; ++i) {
int ki = q.top().second;
std::cout << "index[" << i << "] = " << ki << std::endl;
q.pop();
}
}
which gives output:
index[0] = 3
index[1] = 1
index[2] = 0
The question has the partial answer; that is std::nth_element returns the "the n-th statistic" with a property that none of the elements preceding nth one are greater than it, and none of the elements following it are less.
Therefore, just one call to std::nth_element is enough to get the k largest elements. Time complexity will be O(n) which is theoretically the smallest since you have to visit each element at least one time to find the smallest (or in this case k-smallest) element(s). If you need these k elements to be ordered, then you need to order them which will be O(k log(k)). So, in total O(n + k log(k)).
You can use the basis of the quicksort algorithm to do what you need, except instead of reordering the partitions, you can get rid of the entries falling out of your desired range.
It's been referred to as "quick select" and here is a C++ implementation:
int partition(int* input, int p, int r)
{
int pivot = input[r];
while ( p < r )
{
while ( input[p] < pivot )
p++;
while ( input[r] > pivot )
r--;
if ( input[p] == input[r] )
p++;
else if ( p < r ) {
int tmp = input[p];
input[p] = input[r];
input[r] = tmp;
}
}
return r;
}
int quick_select(int* input, int p, int r, int k)
{
if ( p == r ) return input[p];
int j = partition(input, p, r);
int length = j - p + 1;
if ( length == k ) return input[j];
else if ( k < length ) return quick_select(input, p, j - 1, k);
else return quick_select(input, j + 1, r, k - length);
}
int main()
{
int A1[] = { 100, 400, 300, 500, 200 };
cout << "1st order element " << quick_select(A1, 0, 4, 1) << endl;
int A2[] = { 100, 400, 300, 500, 200 };
cout << "2nd order element " << quick_select(A2, 0, 4, 2) << endl;
int A3[] = { 100, 400, 300, 500, 200 };
cout << "3rd order element " << quick_select(A3, 0, 4, 3) << endl;
int A4[] = { 100, 400, 300, 500, 200 };
cout << "4th order element " << quick_select(A4, 0, 4, 4) << endl;
int A5[] = { 100, 400, 300, 500, 200 };
cout << "5th order element " << quick_select(A5, 0, 4, 5) << endl;
}
OUTPUT:
1st order element 100
2nd order element 200
3rd order element 300
4th order element 400
5th order element 500
EDIT
That particular implementation has an O(n) average run time; due to the method of selection of pivot, it shares quicksort's worst-case run time. By optimizing the pivot choice, your worst case also becomes O(n).
The standard library won't get you a list of indices (it has been designed to avoid passing around redundant data). However, if you're interested in n largest elements, use some kind of partitioning (both std::partition and std::nth_element are O(n)):
#include <iostream>
#include <algorithm>
#include <vector>
struct Pred {
Pred(int nth) : nth(nth) {};
bool operator()(int k) { return k >= nth; }
int nth;
};
int main() {
int n = 4;
std::vector<int> v = {5, 12, 27, 9, 4, 7, 2, 1, 8, 13, 1};
// Moves the nth element to the nth from the end position.
std::nth_element(v.begin(), v.end() - n, v.end());
// Reorders the range, so that the first n elements would be >= nth.
std::partition(v.begin(), v.end(), Pred(*(v.end() - n)));
for (auto it = v.begin(); it != v.end(); ++it)
std::cout << *it << " ";
std::cout << "\n";
return 0;
}
You can do this in O(n) time with a single order statistic calculation:
Let r be the k-th order statistic
Initialize two empty lists bigger and equal.
For each index i:
If array[i] > r, add i to bigger
If array[i] = r, add i to equal
Discard elements from equal until the sum of the lengths of the two lists is k
Return the concatenation of the two lists.
Naturally, you only need one list if all items are distinct. And if needed, you could do tricks to combine the two lists into one, although that would make the code more complicated.
Even though the following code might not fulfill the desired complexity constraints it might be an interesting alternative for the before-mentioned priority queue.
#include <queue>
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
std::vector<int> largestIndices(const std::vector<double>& values, int k) {
std::vector<int> ret;
std::vector<std::pair<double, int>> q;
int index = -1;
std::transform(values.begin(), values.end(), std::back_inserter(q), [&](double val) {return std::make_pair(val, ++index); });
auto functor = [](const std::pair<double, int>& a, const std::pair<double, int>& b) { return b.first > a.first; };
std::make_heap(q.begin(), q.end(), functor);
for (auto i = 0; i < k && i<values.size(); i++) {
std::pop_heap(q.begin(), q.end(), functor);
ret.push_back(q.back().second);
q.pop_back();
}
return ret;
}
int main()
{
std::vector<double> values = { 7,6,3,4,5,2,1,0 };
auto ret=largestIndices(values, 4);
std::copy(ret.begin(), ret.end(), std::ostream_iterator<int>(std::cout, "\n"));
}