You could write like this, for example
#include <iostream> #include <iterator> #include <algorithm> #include <array> #include <functional> int main() { int a[][3] = { { 1, 2, 3 }, { 1, 1, 3 } }; for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::sort( reinterpret_cast<std::array<int, 3> *>( std::begin( a ) ), reinterpret_cast<std::array<int, 3> *>( std::end( a ) ), std::less<>() ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::sort( reinterpret_cast<std::array<int, 3> *>( std::begin( a ) ), reinterpret_cast<std::array<int, 3> *>( std::end( a ) ), std::greater<>() ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; }
The output of the program to the console:
1 2 3 1 1 3 1 1 3 1 2 3 1 2 3 1 1 3
As you can see, first the array is sorted in ascending order, and then in descending order, using standard functional objects std::less
(it could not be used at all, because operator
<would be used instead, declared for the class std::array
) and std::greater
.
The problem is that interpreting a pointer to a one-dimensional array as a pointer to an object std::array
and then accessing the elements of the object through this pointer is not entirely correct in C ++, although the program has successfully completed.
As for arrays, the problem is not that the std::swap
function cannot be applied to them, it can be successfully applied to arrays, but that the sorted elements must be MoveConstructible
and MoveAssignable
, that is, in the appendix to arrays this means that arrays must be assignable or initialized with other arrays. However, for arrays, there is no move assignment operator and no move constructor.
In the example I showed with std::array
this problem does not exist, since this class has an implicitly defined by the compiler relocation assignment operator and a relocation constructor.
I gave this example so that you could declare an array of objects std::array<int, maxM>
. for example
#include <array> //... std::array<int, maxM> M[maxN];
and then without problems could cause function std::sort
.
Therefore, if you want to sort the two-dimensional array, then you will have to write the sorting function yourself, or use the standard C function qsort
, declared in the header file <cstdlib>
.
I will show a simplified version, when the number of compared elements in the array row coincides with the dimension of the array string. In your case, this is not the case; therefore, in the corporate functions you should take into account the number of actually compared elements. These numbers can be included in these functions by calling inside other functions that return a given value of the number of actually compared elements in an array string.
#include <iostream> #include <cstdlib> const int maxN = 2, maxM = 3; int cmp_ascending( const void *lhs, const void *rhs ) { const int ( *a )[maxM] = reinterpret_cast<const int ( * )[maxM]>( lhs ); const int ( *b )[maxM] = reinterpret_cast<const int ( * )[maxM]>( rhs ); const int *first1 = *a, *last1 = *a + maxM; const int *first2 = *b; while ( first1 != last1 && *first1 == *first2 ) ++first1, ++first2; return first1 == last1 ? 0 : ( *first1 > *first2 ) - ( *first1 < *first2 ); } int cmp_descending( const void *lhs, const void *rhs ) { const int ( *a )[maxM] = reinterpret_cast<const int ( * )[maxM]>( lhs ); const int ( *b )[maxM] = reinterpret_cast<const int ( * )[maxM]>( rhs ); const int *first1 = *a, *last1 = *a + maxM; const int *first2 = *b; while ( first1 != last1 && *first1 == *first2 ) ++first1, ++first2; return first1 == last1 ? 0 : ( *first2 > *first1 ) - ( *first2 < *first1 ); } int main() { int a[][3] = { { 1, 2, 3 }, { 1, 1, 3 } }; for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::qsort( a, maxN, sizeof( *a ), cmp_ascending ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; std::qsort( a, maxN, sizeof( *a ), cmp_descending ); for ( const auto &row : a ) { for ( int x : row ) std::cout << x << ' '; std::cout << std::endl; } std::cout << std::endl; }
The output to the console will be the same as in the previous program:
1 2 3 1 1 3 1 1 3 1 2 3 1 2 3 1 1 3
You could bypass these difficulties if you dynamically allocated an array of pointers to one-dimensional arrays.
Otherwise, if you do not want to mess around with arrays, then it is better to use the standard class std::vector<std::vector<int>>
So you have the following four possibilities.
The first is to declare an array of objects of the class std::array
std::array<int, maxM> M[maxN];
In this case, there will be no problems with sorting.
The second is to declare an array of pointers, and then initialize each array pointer to the address of a dynamically allocated one-dimensional array. for example
int * M[mxN]; for ( int i = 0; i < maxN; i++ ) M[i] = new int[maxM];
In this case, there will be no problems with std::sort
.
The third is to leave the array declaration as it is in your program, and use the standard C function qsort
declared in the <cstdlib>
header
Fourth - use the standard std::vector
container to include the following declaration in the program
std::vector<std::vector<int>> M( maxN, std::vector<int>( maxM ) );