Split Parity Function ordering odds and evens - c++

I've been staring at this and I can't figure out what i'm doing wrong. I'm trying to write a function that reorders odd to be in front of evens in the array. The inner order of odds and evens is not important meaning [3, 1, 4, 2] or [1, 3, 2, 4] are both acceptable.
Currently if I initialize int arr[5] = {3,6,4,1,12} I get an output of 3,4,1,6,2 Struggling to figure out what I'm doing wrong.
Code below:
void SplitParity(int arr[], int arrSize)
{
int tempValueHolder;
for (int indexCounter = 0; indexCounter < arrSize; indexCounter++)
{
//Iterate through each index checking for odd
if (arr[indexCounter] % 2 == 0)
{
tempValueHolder = arr[indexCounter];
//If Odd.....shift all indexes forward and move current to the back
for (int innerCounter = indexCounter; innerCounter < arrSize; innerCounter++)
arr[innerCounter] = arr[innerCounter + 1];
arr[arrSize - 1] = tempValueHolder;
}
}
}

You forgot that after shifting everything, you must look at indexCounter once again (you don't know if the value that arrived in the first iteration of the loop when you did arr[indexCounter] = arr[indexCounter+ 1]; is correct or not)
Simplest fix is to add indexCounter --; just after arr[arrSize - 1] = tempValueHolder;
It's also incredibly innefficient and I suggest you look at std::partition

Use standard algorithms with the correct custom comparison function:
#include <iterator>
#include <iostream>
#include <algorithm>
template<class T>
bool is_odd(const T& value)
{
if (value & 1)
return true;
return false;
}
struct odd_first
{
template<class T>
bool operator()(const T& l, const T& r) const {
if (is_odd(l))
{
if (is_odd(r))
return false;
return true;
}
else
return false;
}
};
int main()
{
int vals[] = { 5, 6, 7, 8, 9, 1, 2, 3, 4, 0 };
std::sort(std::begin(vals), std::end(vals), odd_first());
std::copy(std::begin(vals), std::end(vals), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
expected output:
5, 7, 9, 1, 3, 6, 8, 2, 4, 0,
As per Fezvez's suggestion, std::partition:
#include <iterator>
#include <iostream>
#include <algorithm>
struct is_odd
{
template<class T>
bool operator()(const T& value) const
{
if (value & 1)
return true;
return false;
}
};
int main()
{
int vals[] = { 5, 6, 7, 8, 9, 1, 2, 3, 4, 0 };
std::partition(std::begin(vals), std::end(vals), is_odd());
std::copy(std::begin(vals), std::end(vals), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}

You can do this much, much easier with std::sort: Demo
std::sort(std::begin(arr), std::end(arr), [](int lhs, int rhs){
return (lhs % 2 == 1 && rhs % 2 == 0);
});
Output:
3 1 6 4 12
Or, if you desire internal sorting within odd and even: Demo
std::sort(std::begin(arr), std::end(arr), [](int lhs, int rhs){
int l_res = lhs % 2;
int r_res = rhs % 2;
if (l_res == r_res)
return lhs < rhs;
return (l_res == 1 && r_res == 0);
});
Output:
1 3 4 6 12

Related

How can I change the value of the second array after sorting the first one? [duplicate]

This question already has answers here:
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
(9 answers)
Closed 9 months ago.
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);
}

C++: generate multidimensional vector of unknown depth

I have a function in C++ (call it
"weightmatrix") that takes a vector of size n as input, which contains a series of numbers a, b, c..., and returns an n-dimensional vector made up of subvectors of size c, b, a...
That was complicated sounding. Basically, in practice it should look like this:
vector<int> vector_sizes = {2, 3, 1};
cout << "Resulting matrix: " << weightmatrix(vector_sizes); // Function takes vector of size 3
/* Returns the following 3 dimensional matrix:
{ { {0, 0},
{0, 0},
{0, 0} },
{0, 0, 0} }
*/
It's a weird one, I know. I just need to generate a vector without knowing beforehand how many dimensions it will be. Any help or advice you could throw in my way would be awesome.
Here is a solution using a template MultiVector class that returns a MultiVectorView from it's operator[].
The underlying data is stored in a plain std::vector but can be accessed with the vec[x][y][z] syntax.
There is no checking for correct usage, and only very basic functionality is implemented but it gives an idea how it could be done.
#include <iostream>
#include <vector>
template <typename T>
class MultiVector;
template <typename T>
class MultiVectorView {
public:
MultiVectorView(MultiVector<T>& vec_, int index_, int dimension_) : vec(vec_), index(index_), dimension(dimension_) {}
MultiVector<T>& vec;
int index;
int dimension;
MultiVectorView& operator[](std::size_t n_index) {
int index_multiplyer = 1;
for (int i=0; i<dimension; ++i)
index_multiplyer *= vec.dimensions[i];
index += n_index*index_multiplyer;
dimension++;
return *this;
}
operator T() {
return vec.content[index];
}
MultiVectorView& operator=(T val) {
vec.content[index] = val;
return *this;
}
};
template <typename T>
class MultiVector {
public:
MultiVector(std::vector<int> dimensions_) : dimensions(dimensions_) {
int size = dimensions[0];
for (int i = 1; i<dimensions.size(); ++i)
size *= dimensions[i];
content.resize(size);
}
MultiVectorView<T> operator[](std::size_t index) {
return MultiVectorView<T>(*this, index, 1);
}
std::vector<T> content;
std::vector<int> dimensions;
};
int main() {
std::vector<int> v = {2,3,2};
MultiVector<int> test(v);
int tmp = 0;
for (int x = 0; x < v[0]; ++x)
for (int y = 0; y < v[1]; ++y)
for (int z = 0; z < v[2]; ++z) {
test[x][y][z] = tmp++;
}
for (int i=0; i<test.content.size(); ++i)
std::cout << std::endl << test.content[i] << " ";
int b = test[1][2][1];
std::cout << std::endl << "b = " << b << std::endl << "test[0][1][1] = " << test[0][1][1] << std::endl;
}
I took the hint of Galik to make a small sample:
#include <cassert>
#include <iostream>
#include <vector>
template <typename ELEM>
class NDArrayT {
private:
// dimensions
std::vector<size_t> _dims;
// data
std::vector<ELEM> _data;
public:
NDArrayT(const std::vector<size_t> &dims):
_dims(dims)
{
size_t size = _dims.empty() ? 0 : 1;
for (size_t dim : _dims) size *= dim;
_data.resize(size);
}
NDArrayT(
const std::vector<size_t> &dims,
const std::vector<ELEM> &data):
NDArrayT<ELEM>(dims)
{
assert(_data.size() == data.size());
std::copy(data.begin(), data.end(), _data.begin());
}
ELEM& operator[](const std::vector<size_t> &indices)
{
size_t i = 0, j = 0;
for (size_t n = _dims.size(); j < n; ++j) {
i *= _dims[j]; i += indices[j];
}
return _data[i];
}
const ELEM& operator[](const std::vector<size_t> &indices) const
{
size_t i = 0, j = 0;
for (size_t n = _dims.size(); j < n; ++j) {
i *= _dims[j]; i += indices[j];
}
return _data[i];
}
};
using namespace std;
ostream& operator<<(ostream &out, const vector<size_t> &values)
{
const char *sep = "";
for (size_t value : values) {
out << sep << value; sep = ", ";
}
return out;
}
bool inc(vector<size_t> &indices, const vector<size_t> &dims)
{
for (size_t i = indices.size(); i--;) {
if (++indices[i] < dims[i]) return false;
indices[i] = 0;
}
return true; // overflow
}
int main()
{
// build sample data
vector<double> data(2 * 3 * 4);
for (size_t i = data.size(); i--;) data[i] = (double)i;
// build sample array
typedef NDArrayT<double> NDArrayDouble;
const vector<size_t> dims = { 2, 3, 4 };
NDArrayDouble a(dims, data);
// print sample array (check subscript)
vector<size_t> indices(dims.size(), 0);
do {
cout << "a[" << indices << "]: " << a[indices] << endl;
} while (!inc(indices, dims));
// done
return 0;
}
Compiled and tested on ideone.
Output is:
a[0, 0, 0]: 0
a[0, 0, 1]: 1
a[0, 0, 2]: 2
a[0, 0, 3]: 3
a[0, 1, 0]: 4
a[0, 1, 1]: 5
a[0, 1, 2]: 6
a[0, 1, 3]: 7
a[0, 2, 0]: 8
a[0, 2, 1]: 9
a[0, 2, 2]: 10
a[0, 2, 3]: 11
a[1, 0, 0]: 12
a[1, 0, 1]: 13
a[1, 0, 2]: 14
a[1, 0, 3]: 15
a[1, 1, 0]: 16
a[1, 1, 1]: 17
a[1, 1, 2]: 18
a[1, 1, 3]: 19
a[1, 2, 0]: 20
a[1, 2, 1]: 21
a[1, 2, 2]: 22
a[1, 2, 3]: 23
The "arithmetic" to manage multi-dimensional arrays in contiguous memory is actually quite simple. I guess, the most "revolutionary" idea of this sample is the operator[]() which uses a std::vector<size_t> to provide the indices for each dimension.
While I was writing this down, a lot of alternatives for indexing came in my mind. – There is much space for fantasy...
E.g. for linear (one-dimensional) access, a second operator[] for size_t might be provided as well.

Custom binary search in vector

Suppose I have a vector<int> myVec. Let there be n elements in it. I know that these elements are in sorted order(ascending) and also that they are unique. Let n = 10 and myVec be {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}. I'm given l and r such that 0<=l<=r<=n-1. Now i want to search an element val in the subvector that is defined by the bounds l and rsuch that
if val is found return val
if val is not found then return (if possible) a value in the subvector which is just smaller than val.
Return false(or -1 maybe) if either of the above is not possible.
In the above case if if l = 3 and r = 5. The subvector is {8, 10, 12}. If val = 8 return 8. If val = 7 return false (or -1). If val = 9 return 8.
How do I implement this. I want order comparable to binary search. Also, is it possible to use std::binary_search() present under algorithm header file.
something like this?
int search(int l, int r, int value) {
if (l > vec.Size() || r > vec.Size() || l > r) return -1;
for (int i = r; i >= l; --i) {
int v = vector[i];
if (v <= value) return v;
}
return -1;
}
or does it need to be binary?
int BinarySearch(int l, int r, int value) {
return PrivateBinarySearch(l, r, (l+r)/2, value);
}
int PrivateBinarySearch(int l, int r, int index, int value) {
if (vector[index] == value) return value;
else if (vector[index] > value) {
if (index == l) return -1;
else if (index == r) return -1;
else return PrivateBinarySearch(l, index, (index-1+l)/2, value);
}
else { // vector[index] < value
if (index == l) return vector[index];
else if (index == r) return vector[index];
else return PrivateBinarySearch(index, r, (index+1+r)/2, value);
}
Hope this helps
This should work for you and is pretty extensible and flexible:
template<typename T>
typename vector<T>::const_iterator
find_or_under (typename vector<T>::const_iterator start, typename vector<T>::const_iterator end,
const T& val)
{
auto el = std::lower_bound(start, end, val);
//if not found, propagate
if (el == end)
return el;
//if it's equal, just return the iterator
if ((*el) == val)
return el;
//if there is no value of an equal or smaller size, return the end
if (el == start)
return end;
//otherwise, return the previous element
return el-1;
}
//Functor representing the search
struct CustomSearch
{
//Create a searcher from a subrange
CustomSearch (const vector<int> &v, size_t l, size_t r)
{
start = std::lower_bound(std::begin(v), std::end(v), l);
end = find_or_under(start, std::end(v), r) + 1;
}
//Calling the searcher
//Returns this->end on not found
auto operator() (int val)
{
return find_or_under(start, end, val);
}
vector<int>::const_iterator start;
vector<int>::const_iterator end;
};
int main() {
vector<int> v = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
CustomSearch searcher {v, 3, 8};
cout << *searcher(6);
}
Using traditional binary search with minor modification:
#include <iostream>
#include <vector>
int search(const std::vector<int> &vec, int l, int r, int val)
{
int pivot, xl = l, xr = r, mid;
do {
/* Not exact match, check if the closest lower match is in the
* subvector. */
if (xl > xr) {
return xr >= l ? vec[xr]: -1;
}
mid = (xl + xr) / 2;
pivot = vec[mid];
if (val < pivot) {
xr = mid - 1;
} else if (val > pivot) {
xl = mid + 1;
} else if (val == pivot) {
return val;
}
} while (true);
}
int main()
{
std::vector<int> myVec(10);
myVec[0] = 2;
myVec[1] = 4;
myVec[2] = 6;
myVec[3] = 8;
myVec[4] = 10;
myVec[5] = 12;
myVec[6] = 14;
myVec[7] = 16;
myVec[8] = 18;
myVec[9] = 20;
int l = 3, r = 5;
std::cout << "search(3, 5, 8) = " << search(myVec, 3, 5, 8) << std::endl;
std::cout << "search(3, 5, 7) = " << search(myVec, 3, 5, 7) << std::endl;
std::cout << "search(3, 5, 9) = " << search(myVec, 3, 5, 9) << std::endl;
return 0;
}
enter code here

Passing a Truncated Vector by Reference

I'm trying to figure out if there's a way to pass a truncated vector by reference so that it still changes the original vector.
Here's a simplified example of what I'm trying to do. I want the vector
x = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
when the function exits. When my code finishes, though, I get
{ 1, 8, 7, 6, 5, 4, 3, 2, 1, 0 }.
#include <iostream>
#include <vector>
using namespace std;
void example(vector<int> &x)
{
vector<int>::iterator ii = x.begin();
vector<int>::iterator jj = x.end();
if (ii == jj) { return; }
else {
*ii = 1;
example(vector<int>(ii + 1, jj));
}
}
int main()
{
vector<int> x = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
example(x);
for (vector<int>::iterator ii = x.begin(); ii != x.end(); ii++)
cout << *ii << " ";
cout << endl;
}
Any thoughts?
On this line
example(vector<int>(ii + 1, jj));
You are creating a new vector in each call, thus not altering the one passed in to the originating call.
I think if you want to pass part of a vector and retain the original vector you can either pass indexes or iterators.
Here are 2 possible solutions.
#include <iostream>
#include <vector>
using namespace std;
void example2(vector<int>& x, int ind = 0)
{
if (ind < x.size())
{
x[ind] = 1;
example2(x, ind + 1);
} else
{
return;
}
}
void example(vector<int>::iterator start, vector<int>::iterator end)
{
if (start == end)
{
return;
} else
{
*start = 1;
example(++start, end);
}
}
int main()
{
vector<int> x = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
example(x.begin(), x.end());
//example2(x);
for (vector<int>::iterator ii = x.begin(); ii != x.end(); ii++)
cout << *ii << " ";
cout << endl;
}
I see a recursion and any call of example(vector<int>(ii + 1, jj)); creates new vector (particularly this vector<int>(ii + 1, jj) is unnamed vector created on the base of initial x), so it is impossible to get in main what you want with your code

Sorting two corresponding arrays [duplicate]

This question already has answers here:
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
(9 answers)
Closed 9 months ago.
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);
}