Sort matrix defined as <double> vector
Suppose I have a square matrix A size n , defined as std::vector<double> .
std::vector<double> A(n*n); Access to the matrix elements is carried out in the usual way:
double a_ij = A[i*n + j]; I need to sort the rows of a matrix in ascending order with respect to the first column.
The qsort function allows me to do this using arrays and function pointers, but I would like to find a way to accomplish this using vectors and std::sort .
Also note that I do not want to define my matrix as a vector of vectors for performance reasons.
Edit:
Function passed to qsort:
static int comparisonFunction(const void* firstRow, const void* secondRow) { if (((double *)firstRow)[0] < ((double *)secondRow)[0]) return -1; else if (((double *)secondRow)[0] < ((double *)firstRow)[0]) return 1; return 0; } And the call:
std::qsort(matrixArray, nbRows, sizeof(double)*nbRows, comparisonFunction); std::sort works with iterators and does not care about iterator implementation. Therefore, if you define a struct RowIter that wraps std::vector<double>& matrix , with the size_t RowSize element size_t RowSize for operator+(size_t) (and operator- , operator++ , etc.) AND Row operator*() const , then std::sort can sort by this iterator.
There is still quite a bit of work than qsort , but it will generalize to non-POD types.
You can replace qsort with std::sort to sort the base array, but you must define:
- Row type, which directly accesses the base storage of the vector - you cannot use the vector here, because even if the array or arrays are still an array, the vector of vectors is not a square size vector. Worse, I donβt know which portable way to assign an existing repository to a vector. This type of string must be constructive and portable, as well as properly supporting the exchange.
- RandomAccessIterator on this type of Row, capable of correctly handling the end of the underlying array.
It is up to you, but all versions of standard C ++ explicitly support the C library, so there is no harm in using qsort in this case, because it is much simpler and, in the end, less of the -prone error. The qsort path requires only 7 lines, which are easy to control and verify. For a pleasant C ++ method, you will need at least 2 classes with non-trivial constructors, so there are much more lines and much more error possibilities in them.
If you really can't use qsort , perhaps for internal encoding rules, I would just copy the data into a vector of vectors, sort them and copy the data back to the original vector. It includes 2 additional full copies of the matrix, but at least uses standard classes and requires much less coding.
The simplest solution is to save qsort() and just use std::vector::data() , which returns a pointer to the first element, which allows you to use std::vector just like a C array:
std::qsort(matrixArray.data(), nbRows, sizeof(double)*nbRows, comparisonFunction); Using std::sort() correct, but verbose, because you will need not only a random access iterator class to iterate over the lines, but also a class that abstracts the line so that std::sort() can exchange them.
By the way, but when using std::sort you need to extract the elements you want to sort into your own std::vector along with the index. Then sort this vector and finally change the order of the rows in the original matrix by the indices in this vector.
#include <vector> #include <tuple> #include <algorithm> const int n = 10; std::vector<double> row_sort(std::vector<double> const& A) { std::vector<std::tuple<int, double> > first_element(n); for(int i = 0; i < n; ++i) { first_element[i] = std::make_tuple(i, A[i*n]); } std::sort(std::begin(first_element), std::end(first_element), [](std::tuple<int, double> const& lhs, std::tuple<int, double> const& rhs) { return std::get<1>(lhs) < std::get<1>(rhs); }); std::vector<double> result(n*n); for(int i = 0; i < n; ++i) { std::copy_n(&A[std::get<0>(first_element[i])*n], n, &result[i*n]); } return result; }