I have this code here that has two arrays. It sorts arr[], so that the highest value will be in index 0. Now the second array arr1[] contains strings, I'd like the code to apply whatever changes where made to arr[] to arr1[]. So that arr[0] would return 6, while arr1[0] would return the string "d1". Notice how "d1" was at the same index as 6? After sorting I'd like the same values to still have their string counterparts.
开发者_运维百科How would I go about doing this?
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <functional>
using namespace std;
int main() {
int arr[ 5 ] = { 4, 1, 3, 6, 2 };
string arr1[ 5 ] = { "a1", "b1", "c1", "d1", "e1" };
std::sort( arr, arr + 5, std::greater< int >() );
cout << arr[0] << arr1[0] << endl;
system("pause");
}
Rather than sort the arrays, sort the indices. I.e., you have
int arr[5]={4,1,3,6,2}
string arr1[5]={"a1","b1","c1","d1","e1"};
and you make
int indices[5]={0,1,2,3,4};
now you make a sort indices comparator that looks like this (just and idea, you'll probably have to fix it a little)
class sort_indices
{
private:
int* mparr;
public:
sort_indices(int* parr) : mparr(parr) {}
bool operator()(int i, int j) const { return mparr[i]<mparr[j]; }
}
now you can use the stl sort
std::sort(indices, indices+5, sort_indices(arr));
when you're done, the indices array will be such that arr[indices[0]]
is the first element. and likewise arr1[indices[0]]
is the corresponding pair.
This is also a very useful trick when you're trying to sort a large data object, you don't need to move the data around at every swap, just the indices.
You need to combine them together and then sort the combined pair and then un-combine the pairs.
int arr[ 5 ] = { ... };
string arr1[ 5 ] = { ... };
pair<int, string> pairs[ 5 ];
for ( int i = 0; i < 5; ++i )
pairs[ i ] = make_pair( arr[ i ], arr1[ i ] );
sort( pairs.begin(), pairs.end() );
for ( int i = 0; i < 5; ++i )
{
arr[ i ] = pairs[ i ].first;
arr1[ i ] = pairs[ i ].second;
}
Really though, if arr
and arr1
are related then they should be stored as the pair
(or at least a custom struct
) anyway. That way you don't need to use this as an intermediate step.
Write your own iterator and use STD:sort. It's easily coded in less than 50 lines without 3rd party libraries. Swap function IS VERY IMPORTANT here.
#include <iostream>
#include <iterator> // std::iterator, std::input_iterator_tag
#include <algorithm>
using namespace std;
struct Tuple;
struct RefTuple;
#define TUPLE_COMMON_FUNC(C, D, E, F) \
C##::C## (Tuple& t) ##D \
C##::C## (RefTuple& t) ##D \
void C##::operator = (Tuple& t) ##E \
void C##::operator = (RefTuple& t) ##E \
bool C##::operator < (const Tuple& t) const ##F \
bool C##::operator < (const RefTuple& t) const ##F
#define ASSIGN_1 : i(t.i), j(t.j), s(t.s) {}
#define ASSIGN_2 { i = t.i; j = t.j; s = t.s; }
#define SORT_CRITERIA \
return (j < t.j) || (j == t.j && (i < t.i));
struct Tuple {
int i, j, s;
TUPLE_COMMON_FUNC(Tuple, ; , ; , ;)
};
struct RefTuple {
int &i, &j, &s;
RefTuple(int &x, int &y, int &z): i(x), j(y), s(z) {}
TUPLE_COMMON_FUNC(RefTuple, ; , ; , ;)
};
TUPLE_COMMON_FUNC(Tuple, ASSIGN_1, ASSIGN_2, {SORT_CRITERIA})
TUPLE_COMMON_FUNC(RefTuple, ASSIGN_1, ASSIGN_2, {SORT_CRITERIA})
void swap(RefTuple& t1, RefTuple& t2) {
t1.i ^= t2.i; t2.i ^= t1.i; t1.i ^= t2.i;
t1.j ^= t2.j; t2.j ^= t1.j; t1.j ^= t2.j;
t1.s ^= t2.s; t2.s ^= t1.s; t1.s ^= t2.s;
}
class IterTuple : public iterator<random_access_iterator_tag, Tuple> {
int *i, *j, *s, idx;
public:
IterTuple(int* x, int*y, int* z, int l) : i(x), j(y), s(z), idx(l) {}
IterTuple(const IterTuple& e) : i(e.i), j(e.j), s(e.s), idx(e.idx) {}
RefTuple operator*() { return RefTuple(i[idx], j[idx], s[idx]); }
IterTuple& operator ++ () { idx++; return *this; }
IterTuple& operator -- () { idx--; return *this; }
IterTuple operator ++ (int) { IterTuple tmp(*this); idx++; return tmp; }
IterTuple operator -- (int) { IterTuple tmp(*this); idx--; return tmp; }
int operator - (IterTuple& rhs) { return idx - rhs.idx; }
IterTuple operator + (int n) { IterTuple tmp(*this); tmp.idx += n; return tmp; }
IterTuple operator - (int n) { IterTuple tmp(*this); tmp.idx -= n; return tmp; }
bool operator==(const IterTuple& rhs) { return idx == rhs.idx; }
bool operator!=(const IterTuple& rhs) { return idx != rhs.idx; }
bool operator<(IterTuple& rhs) { return idx < rhs.idx; }
};
int Ai[10] = {0, 0, 2, 3, 2, 4, 1, 1, 4, 2};
int Aj[10] = {0, 2, 3, 4, 4, 4, 0, 1, 0, 2};
int Ax[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int main () {
IterTuple from(Ai, Aj, Ax, 0);
IterTuple until(Ai, Aj, Ax, 10);
sort(from, until);
for (IterTuple it = from; it != until; it++)
cout << (*it).i << ' ' << (*it).j << ' ' << (*it).s << '\n';
return 0;
}
I believe that writting your own QuickSort variant is simplier and the result will perform better then mapping custom iterators or array with indices.
QuickSort is not stable sort.
template<class A, class B> void QuickSort2Desc(A a[], B b[], int l, int r)
{
int i = l;
int j = r;
A v = a[(l + r) / 2];
do {
while (a[i] > v)i++;
while (v > a[j])j--;
if (i <= j)
{
std::swap(a[i], a[j]);
std::swap(b[i], b[j]);
i++;
j--;
};
} while (i <= j);
if (l < j)QuickSort2Desc(a, b, l, j);
if (i < r)QuickSort2Desc(a, b, i, r);
}
精彩评论