C++ Sort based on other int array - c++

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]];

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.

Problems with vectors, how to remove the arrays in my vectors?

I have created a function that creates all the possible solutions for a game that I am creating... Maybe some of you know the bullcow game.
First I created a function that creates a combination of numbers of max four integers and the combination can't have any repeating number in it... like...
'1234' is a solution but not '1223' because the '2' is repeating in the number. In total there is 5040 numbers between '0123' and '9999' that haven't repeating numbers.
Here is my function:
std::vector <std::array<unsigned, 4>> HittaAllaLosningar(){
std::vector <std::array<unsigned, 4>> Losningar;
for (unsigned i = 0; i < 10; i++) {
for (unsigned j = 0; j < 10; j++) {
for (unsigned k = 0; k < 10; k++) {
for (unsigned l = 0; l < 10; l++) {
if (i != j && i != k && i != l && j != k && j != l && k != l) {
Losningar.push_back({i,j,k,l});
}
}
}
}
}
return Losningar;
}
Now let's say I have the number '1234' and that is not the solution I am trying to find, I want to remove the solution '1234' from the array since that isn't a solution... how do I do that? have been trying to find for hours and can't find it. I have tried vector.erase but I get errors about unsigned and stuff... also its worth to mention the guesses are in strings.
What I am trying to do is, to take a string that I get from my program and if it isn't a solution I want to remove it from the vector if it exists in the vector.
Here is the code that creates the guess:
std::string Gissning(){
int random = RandomGen();
int a = 0;
int b = 0;
int c = 0;
int d = 0;
for (unsigned i = random-1; i < random; i++) {
for (unsigned j = 0; j < 4; j++) {
if (j == 0) {
a = v[i][j];
}
if (j == 1) {
b = v[i][j];
}
if (j == 2) {
c = v[i][j];
}
if (j == 3) {
d = v[i][j];
}
}
std::cout << std::endl;
AntalTry++;
}
std::ostringstream test;
test << a << b << c << d;
funka = test.str();
return funka;
}
The randomgen function is just a function so I can get a random number and then I go in the loop so I can take the element of the vector and then I get the integers of the array.
Thank you very much for taking your time to help me, I am very grateful!
You need to find the position of the element to erase.
std::array<unsigned, 4> needle{1, 2, 3, 4};
auto it = std::find(Losningar.begin(), Losningar.end(), needle);
if (it != Losningar.end()) { Losningar.erase(it); }
If you want to remove all the values that match, or you don't like checking against end, you can use std::remove and the two iterator overload of erase. This is known as the "erase-remove" idiom.
std::array<unsigned, 4> needle{1, 2, 3, 4};
Losningar.erase(std::remove(Losningar.begin(), Losningar.end(), needle), Losningar.end());
To erase from a vector you just need to use erase and give it an iterator, like so:
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
auto it = vec.begin(); //Get an iterator to first elements
it++; //Increment iterator, it now points at second element
it = vec.erase(it); // This erases the {4,3,2,1} array
After you erase the element, it is invalid because the element it was pointing to has been deleted. Ti continue to use the iterator you can take the return value from the erase function, a valid iterator to the next element after the one erased, in this the case end iterator.
It is however not very efficient to remove elements in the middle of a vector, due to how it works internally. If it's not important in what order the different solution are stored, a small trick can simplify and make your code faster. Let's say we have this.
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
vec.push_back({3,2,1,4});
To remove the middle one we then do
vec[1] = vec.back(); // Replace the value we want to delete
// with the value in the last element of the vector.
vec.pop_back(); //Remove the last element
This is quite simple if you have ready other functions:
using TestNumber = std::array<unsigned, 4>;
struct TestResult {
int bulls;
int cows;
}
// function which is used to calculate bulls and cows for given secred and guess
TestResult TestSecretGuess(const TestNumber& secret,
const TestNumber& guess)
{
// do it your self
… … …
return result;
}
void RemoveNotMatchingSolutions(const TestNumber& guess, TestResult result)
{
auto iter =
std::remove_if(possibleSolutions.begin(),
possibleSolutions.end(),
[&guess, result](const TestNumber& possibility)
{
return result == TestSecretGuess(possibility, guess);
});
possibleSolutions.erase(iter, possibleSolutions.end());
}
Disclaimer: it is possible to improve performance (you do not care about order of elements).

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

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;
}
}
}

Arranging by indexes vector

I have two vectors: a vector and index vector. How can I make the vector be arranged by the indexes vector? Like:
Indexes 5 0 2 1 3 4
Values a b c d e f
Values after operation b d c e f a
The indexes vector will always contain the range [0, n) and each index only once.
I need this operation to be done in place because the code is going to be run on a device with low memory.
How can I do this in c++? I can use c++11
Since you know that your index array is a permutation of [0, N), you can do this in linear time and in-place (plus one temporary) by working cycle-by-cycle. Something like this:
size_t indices[N];
data_t values[N];
for (size_t pos = 0; pos < N; ++pos) // \
{ // } this loops _over_ cycles
if (indices[pos] == pos) continue; // /
size_t i = pos;
const data_t tmp = values[pos];
while (true) // --> this loops _through_ one cycle
{
const size_t next = indices[i];
indices[i] = i;
values[i] = values[next];
if (next == pos) break;
i = next;
}
values[i] = tmp;
}
This implementation has the advantage over using swap each time that we only need to use the temporary variable once per cycle.
If the data type is move-only, this still works if all the assignments are surrounded by std::move().
std::vector<int> indices = { 5, 0, 2, 1, 3, 4};
std::vector<char> values = {'a', 'b', 'c', 'd', 'e', 'f'};
for(size_t n = 0; n < indices.size(); ++n)
{
while(indices[n] != n)
{
std::swap(values[n], values[indices[n]]);
std::swap(indices[n], indices[indices[n]]);
}
}
EDIT:
I think this should be O(n), anyone disagree?
for(int i=0;i<=indexes.size();++i)
for(int j=i+1;j<=indexes.size();++j)
if(indexes[i] > indexes[j] )
swap(indexes[i],indexes[j]),
swap(values[i],values[j]);
It's O(N²) complexity, but should work fine on small number values.
You can also pass a comparison function to the C++ STL sort function if you want O(N*logN)
You can just sort the vector, your comparison operation should compare the indices. Of course, when moving the data around, you have to move the indices, too.
At the end, your indices will be just 0, 1, ... (n-1), and the data will be at the corresponding places.
As implementation note: you can store the values and indices together in a structure:
struct SortEntry
{
Data value;
size_t index;
};
and define the comparison operator to look only at indices:
bool operator< (const SortEntry& lhs, const SortEntry& rhs)
{
return lhs.index < rhs.index;
}
This solution runs in O(n) time:
int tmp;
for(int i = 0; i < n; i++)
while(indexes[i] != i){
swap(values[i], values[indexes[i]]);
tmp = indexes[i];
swap(indexes[i], indexes[tmp]);
}
This will run in O(n) time without any error.Check it on ideone
int main(int argc, char *argv[])
{
int indexes[6]={2,3,5,1,0,4};
char values[6]={'a','b','c','d','e','f'};
int result[sizeof(indexes)/4]; //creating array of size indexes or values
int a,i;
for( i=0;i<(sizeof(indexes)/4);i++)
{
a=indexes[i]; //saving the index value at i of array indexes
result[a]=values[i]; //saving the result in result array
}
for ( i=0;i<(sizeof(indexes)/4);i++)
printf("%c",result[i]); //printing the result
system("PAUSE");
return 0;
}

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);