How to find indexes of 5 the biggest elements in vector? - c++

How to find indexes of 5 the biggest elements in vector ?
For example std::vector<int> how to find indexes of 5 biggest values but not to change original vector ?

std::partial_sort( v.begin(), v.begin()+5, v.end() ) sorts a vector in a way, that the 5 smallest values are sorted and at the beginning of v. The rest is left unsorted.
Since you want the indices and keep the original:
Fill a new vector with numbers from 0..n-1 and supply a comparison function that does v[a] > v[b] instead of a > b:
struct Comp{
Comp( const vector<int>& v ) : _v(v) {}
bool operator ()(int a, int b) { return _v[a] > _v[b]; }
const vector<int>& _v;
}
vector<int> vx;
vx.resize(v.size());
for( int i= 0; i<v.size(); ++i ) vx[i]= i;
partial_sort( vx.begin(), vx.begin()+5, vx.end(), Comp(v) );
vx[0..4] contains the indices.

1 solution:
The solution is O(n), where n is the number of elements in the vector being examined.
create a dequeue of vector iterators of length 5, initialized with NULL
read the elements of the vector under examination and push_back the index {the idea is to push the new index in the front or back depending upon whether the new element data read is smaller than rear index's data or greater than the front index's data, if the data already in the dequeue is NULL, then whether you push_front or push_back, it doesn't matter}. This would maintain the dequeue in the sorted from from front to back.
If the new data being read is greater than the front data, then remove the rear and push the current data's iterator in front; else do nothing
At the end of the iteration the dequeue will have top five element's iterators.

You can make a copy from the original vector, and partially sort it with a dedicated algorithm from the STL nth_element :
bool cmp (int i,int j) { return (i<j); }
int main () {
vector<int> myvector;
vector<int>::iterator it;
// set some values:
for (int i=1; i<10; i++) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
random_shuffle (myvector.begin(), myvector.end());
// using default comparison (operator <):
std::vector<int> copy_of_orig = myvector;
nth_element (copy_of_orig.begin(), copy_of_orig.begin()+5, copy_of_orig.end(), cmp);
// Display the first five biggest elts.
for (int i = 0; i < 5; ++i)
std::cout << copy_of_orig[i] << std::endl;
}

There might be a more elegant way, but I'm to tired to find it right now. You could do something like this (untested, so no guarantees it works out of the box, particulary in corner cases, but it should):
std::array<int, 5> indices = {-1,-1,-1,-1,-1};//-1 used as invalid index for cases where myVec.size()<5
for(int i = 0; i < myVec.size(); ++i)
{
for(int j = 0; j < 5; ++j)
if((indices[j] == - 1) || (myVec[i] > myVec[indices[j]]))
{
std::copy_backward(indices.begin() + j, indices.end() - 1, indices.end());
indices[j] = i;
break;
}
}
It maintains a list of the 5 biggest elements. For each element of the vector it will start with the biggest element, test if the new one is bigger, if yes shift the indices down and insert as the first, otherwise test for the second biggest and so on. Doesn't modify the vector and runs in O(n) with pretty low overhead.
In case you can't use C++11, you can always use an std::vector (or int[5] if you really want to) instead of std::array.

You will need to do something like this:
int largestNumbers [5]{0, 0, 0, 0, 0};
for each( const int i in data ){
{
for (int index = 0; index < 5; index++){
if (i > largestNumber[index]){
largestNumber[index] = i;
}
}
}

Related

Pick every element once from sorted array

I have a sorted array and I want to take every element once into an other array
Example:
Input: array[] = { 1,2,2,3,3,5 }
Output: array2[] = { 1,2,3,5 }
Here is my attempt
int db = 0,array2[100];
for(int i = 0;i < k;i++){
int j = 0;
for(j = 0;j < db;j++){
if(array[i] == array2[j]){
break;
}
}
if(i == j){
array2[db] == array[i];
db++;
}
}
/* PRINT
for(int i = 0;i < db;i++){
cout<<array2[i]<<" ";
}
cout<<endl;*/
There's a standard algorithm std::unique_copy that does exactly this:
auto end = std::unique_copy(std::begin(array), std::end(array), array2);
The returned iterator end points to one past the last element that is inserted into array2, so you can calculate the number of unique elements that were copied like this:
auto num = std::distance(array2, end);
I would recommend using std::vector instead of arrays anyway, and then you don't have to worry about computing the number of copied unique elements. In case you use a vector the 3rd argument to the algorihtm would be std::back_inserter(vec).
We can't give you an answer about what happened to your code if we don't know what k is.
But generally, if you want unique values from a sorted array, the quick way to do it is just employ the set.
#include <set>
then set<int, greater<int> > s1;
for (int i: array) s1.insert(i);
this will only add unique value in the new vector in increasing order.

deleting multiple elements in an array

i am trying to write a code that will delete all the elements if an array has same element at different index . it works fine for one element deletion or elements at odd index i.e 1,3,5 etc but it neglects one element if the consecutive index have same element.
i have just tried this to get my hands on arrays
for(int i=0;i<n;i++) //for deletion
{
if(arr[i]==_delete)
{
arr[i]=arr[i+1];
--n;
}
}
I suggest you use std::vector as a container for your objects.
std::vector<TYPE> vec ;
// initialise vector
You can use
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](const auto & item){return item == _delete;}), vec.end());
Alternatively, you can use std::list. Its list::erase has linear time complexity.
As an additional solution, if you want to deal with built-in C++ arrays, the standard std::remove algorithm can be rewritten like this:
void remove(int _delete) {
int j = 0;
for (int i = 0; i < n; ++i) {
if (arr[i] != _delete) {
arr[j++] = arr[i];
}
}
// update the size!
n = j;
}
It's quite pretty:
We keep in the array the elements we only need, and override the ones in which we are not interested (they can be either equal or not to _delete and start at position j till the end)

sorting an array and maintaining element's old index

I have an array A:
A = [10 11 3 15 8 7]
index = 0 1 2 3 4 5
I want to sort this array.After sorting I want the information of old index.For this I can create a structure like this.
struct VnI{
int value;
int index;
};
sorting the array of structure with respect to value solve my problem.But I want to know that is it possible to solve this using sort or any other function in C++11.
I have tried this way:
struct VnI{
int V;
int I;
};
bool comparator(VnI x,VnI y){
if(x.V < y.V)
return true;
return false;
}
int maximumGap(const vector<int> &A) {
vector<VnI> B;
for(int i = 0;i < A.size();i++){
B[i].I = i;
B[i].V = A[i];
}
sort(B.begin(),B.end(),comparator);
for(int i = 0;i < B.size();i++){
cout<<B[i].I<<" "<<B[i].V<<endl;
}
}
But I got runtime error.
Please help.
This code is wrong:
vector<VnI> B;
for(int i = 0;i < A.size();i++){
B[i].I = i;
B[i].V = A[i];
}
When you write B[i], it assumes that B is at least of size i+1. Since the maximum value of i (which you used an index to B) is A.size()-1. The assumption in your code is that B is at least of size A.size(). This assumption is wrong — the fact is that B is of size 0.
Unfortunately operator[] of std::vector doesn't check for out of range index. If you use at(), the code will throw std::out_of_range exception:
vector<VnI> B;
for(int i = 0;i < A.size();i++){
B.at(i).I = i;
B.at(i).V = A[i];
}
Now this would throw std::out_of_range exception.
Anyway, one simple fix could be this:
vector<VnI> B (A.size()); //initialize B with the size of A.
for(int i = 0;i < A.size();i++){
B[i].I = i;
B[i].V = A[i];
}
However, I'd suggest this solution:
vector<VnI> B;
B.reserve(A.size());
for(int i = 0;i < A.size(); i++){
B.emplace_back(i, A[i]);
}
I'd also suggest you read more about std::vector, especially the following functions:
size()
capacity()
resize()
reserve()
push_back()
operator[]
at()
emplace_back()
and all the constructors.
Also, learn to naming your variables properly and be consistent with it.
Hope that helps.
do you pefer to use vector and pair?
each pair has "first" and "second", put "first"=value to sort,"second"=original index, create a pair for each element and put them into vector to sort:
int N[]={10,11,3,15,8,7};
std::vector<std::pair<int,int> > v;
//create pair for each element
for(int i=0;i<sizeof(N)/sizeof(int);i++){
//first is value of array,second is original index
v.push_back(std::make_pair(N[i],i));
}
//sort the vector of pair
sort(v.begin(),v.end());
//get original index from second of pair
for(std::pair<int,int>& p : v){
std::cout << p.first << ":" << p.second << std::endl;
}
output
3:2
7:5
8:4
10:0
11:1
15:3
Normally what is done is the opposite... i.e. given an array x of elements compute an array of integers ix so that x[ix[i]] appears to be sorted under a certain criteria.
This allows representing the container with different orderings without actually having to move/copy the elements.
With C++11 this can easily be done using lambdas:
// Build the index vector ix
std::vector<int> ix(x.size());
for (int i=0,n=x.size(); i<n; i++) ix[i] = i;
// Sort ix according to the corresponding values in x
// (without touching x)
std::sort(ix.begin(), ix.end(),
[&x](int a, int b) { return x[a] < x[b]; });
This ix index array is what you are asking for (i.e. the "old" position of an element: ix[i] is where the i-th element of the sorted list was in the original array) and there is no need to modify the input array.
You are trying to sort a list of custom objects, answerd here:
SO Link
Once you list the list of VnI objects you can then access there old index's through the I member that I presume is the index.

C++ Sort based on other int array

suppose i have two vector
std::vector<int>vec_int = {4,3,2,1,5};
std::vector<Obj*>vec_obj = {obj1,obj2,obj3,obj4,obj5};
How do we sort vec_obj in regard of sorted vec_int position?
So the goal may look like this:
std::vector<int>vec_int = {1,2,3,4,5};
std::vector<Obj*>vec_obj = {obj4,obj3,obj2,obj1,obj5};
I've been trying create new vec_array:
for (int i = 0; i < vec_int.size(); i++) {
new_vec.push_back(vec_obj[vec_int[i]]);
}
But i think it's not the correct solution. How do we do this? thanks
std library may be the best solution,but i can't find the correct solution to implement std::sort
You don't have to call std::sort, what you need can be done in linear time (provided the indices are from 1 to N and not repeating)
std::vector<Obj*> new_vec(vec_obj.size());
for (size_t i = 0; i < vec_int.size(); ++i) {
new_vec[i] = vec_obj[vec_int[i] - 1];
}
But of course for this solution you need the additional new_vec vector.
If the indices are arbitrary and/or you don't want to allocate another vector, you have to use a different data structure:
typedef pair<int, Obj*> Item;
vector<Item> vec = {{4, obj1}, {3, obj2}, {2, obj3}, {1, obj4}, {5, obj5}};
std::sort(vec.begin(), vec.end(), [](const Item& l, const Item& r) -> bool {return l.first < r.first;});
Maybe there is a better solution, but personally I would use the fact that items in a std::map are automatically sorted by key. This gives the following possibility (untested!)
// The vectors have to be the same size for this to work!
if( vec_int.size() != vec_obj.size() ) { return 0; }
std::vector<int>::const_iterator intIt = vec_int.cbegin();
std::vector<Obj*>::const_iterator objIt = vec_obj.cbegin();
// Create a temporary map
std::map< int, Obj* > sorted_objects;
for(; intIt != vec_int.cend(); ++intIt, ++objIt )
{
sorted_objects[ *intIt ] = *objIt;
}
// Iterating through map will be in order of key
// so this adds the items to the vector in the desired order.
std::vector<Obj*> vec_obj_sorted;
for( std::map< int, Obj* >::const_iterator sortedIt = sorted_objects.cbegin();
sortedIt != sorted_objects.cend(); ++sortedIt )
{
vec_obj_sorted.push_back( sortedIt->second );
}
[Not sure this fits your usecase, but putting the elements into a map will store the elements sorted by key by default.]
Coming to your precise solution if creation of the new vector is the issue you can avoid this using a simple swap trick (like selection sort)
//Place ith element in its place, while swapping to its position the current element.
for (int i = 0; i < vec_int.size(); i++) {
if (vec_obj[i] != vec_obj[vec_int[i])
swap_elements(i,vec_obj[i],vec_obj[vec_int[i]])
}
The generic form of this is known as "reorder according to", which is a variation of cycle sort. Unlike your example, the index vector needs to have the values 0 through size-1, instead of {4,3,2,1,5} it would need to be {3,2,1,0,4} (or else you have to adjust the example code below). The reordering is done by rotating groups of elements according to the "cycles" in the index vector or array. (In my adjusted example there are 3 "cycles", 1st cycle: index[0] = 3, index[3] = 0. 2nd cycle: index[1] = 2, index[2] = 1. 3rd cycle index[4] = 4). The index vector or array is also sorted in the process. A copy of the original index vector or array can be saved if you want to keep the original index vector or array. Example code for reordering vA according to vI in template form:
template <class T>
void reorder(vector<T>& vA, vector<size_t>& vI)
{
size_t i, j, k;
T t;
for(i = 0; i < vA.size(); i++){
if(i != vI[i]){
t = vA[i];
k = i;
while(i != (j = vI[k])){
// every move places a value in it's final location
vA[k] = vA[j];
vI[k] = k;
k = j;
}
vA[k] = t;
vI[k] = k;
}
}
}
Simple still would be to copy vA to another vector vB according to vI:
for(i = 0; i < vA.size(); i++){
vB[i] = vA[vI[i]];

how would I sort a list and get the top K elements? (STL)

I have a vector of doubles. I want to sort it from highest to lowest, and get the indices of the top K elements. std::sort just sorts in place, and does not return the indices I believe. What would be a quick way to get the top K indices of largest elements?
you could use the nth_element STL algorithm - this will return you the N greatest elements ( this is the fastest way,using stl ) and then use .sort on them,or you could use the partial_sort algorithm,if you want the first K elements to be sorted (:
Using just .sort is awful - it is very slow for the purpose you want.. .sort is great STL algorithm,but for sorting the whole container,not just the first K elements (; it's not an accident the existung of nth_element and partial_sort ;)
The first thing that comes to mind is somewhat hackish, but you could define a struct that stored both the double and its original index, then overload the < operator to sort based on the double:
struct s {
double d;
int index;
bool operator < (const struct &s) const {
return d < s.d;
}
};
Then you could retrieve the original indices from the struct.
Fuller example:
vector<double> orig;
vector<s> v;
...
for (int i=0; i < orig.size(); ++i) {
s s_temp;
s_temp.d = orig[i];
s_temp.index = i;
v.push_back(s);
}
sort(v.begin(), v.end());
//now just retrieve v[i].index
This will leave them sorted from smallest to largest, but you could overload the > operator instead and then pass in greater to the sort function if wanted.
OK, how about this?
bool isSmaller (std::pair<double, int> x, std::pair<double, int> y)
{
return x.first< y.first;
}
int main()
{
//...
//you have your vector<double> here, say name is d;
std::vector<std::pair<double, int> > newVec(d.size());
for(int i = 0; i < newVec.size(); ++i)
{
newVec[i].first = d[i];
newVec[i].second = i; //store the initial index
}
std::sort(newVec.begin(), newVec.end(), &isSmaller);
//now you can iterate through first k elements and the second components will be the initial indices
}
Not sure about pre-canned algorithms, but take a look at selection algorithms; if you need the top K elements of a set of N values and N is much larger than K, there are much more efficient methods.
If you can create an indexing class (like #user470379's answer -- basically a class that encapsulates a pointer/index to the "real" data which is read-only), then use a priority queue of maximum size K, and add each unsorted element to the priority queue, popping off the bottom-most element when the queue reaches size K+1. In cases like N = 106, K = 100, this handles cases much more simply + efficiently than a full sort.
So you actually need a structure that maps indices to corresponding doubles.
You could use std::multimap class to perform this mapping. As Jason have noted std::map does not allow duplicate keys.
std::vector<double> v; // assume it is populated already
std::multimap<double, int> m;
for (int i = 0; i < v.size(); ++i)
m.insert(std::make_pair(v[i], i));
...
After you've done this you could iterate over first ten elements as map preserves sorting of keys to the elements.
Use multimap for vector's (value, index) to handle dups. Use reverse iterators to walk results in descending order.
#include <multimap>
#include <vector>
using namespace std;
multimap<double, size_t> indices;
vector<double> values;
values.push_back(1.0);
values.push_back(2.0);
values.push_back(3.0);
values.push_back(4.0);
size_t i = 0;
for(vector<double>::const_iterator iter = values.begin();
iter != values.end(); ++iter, ++i)
{
indices.insert(make_pair<double,int>(*iter, i));
}
i = 0;
size_t limit = 2;
for (multimap<double, size_t>::const_reverse_iterator iter = indices.rbegin();
iter != indices.rend() && i < limit; ++iter, ++i)
{
cout << "Value " << iter->first << " index " << iter->second << endl;
}
Output is
Value 4 index 3
Value 3 index 2
If you just want the vector indices after sort, use this:
#include <algorithm>
#include <vector>
using namespace std;
vector<double> values;
values.push_back(1.0);
values.push_back(2.0);
values.push_back(3.0);
values.push_back(4.0);
sort(values.rbegin(), values.rend());
The top K entries are indexed by 0 to K-1, and appear in descending order. This uses reverse iterators combined with standard sort (using less<double> to achieve descending order when iterated forward. Equivalently:
sort(values.rbegin(), values.rend(), less<double>());
Sample code for the excellent nth_element solution suggested by #Kiril here (K = 125000, N = 500000). I wanted to try this out, so here it is.
vector<double> values;
for (size_t i = 0; i < 500000; ++i)
{
values.push_back(rand());
}
nth_element(values.begin(), values.begin()+375000, values.end());
sort(values.begin()+375000, values.end());
vector<double> results(values.rbegin(), values.rbegin() + values.size() - 375000);