web-dev-qa-db-ja.com

組み込み関数(または他の方法)を使用してC ++で2D配列を並べ替えますか?

私は以下のような2D配列を持っています。 (array[5][2]

20  11    
10  20
39  14
29  15
22  23

ソート後は以下のようになります。

10  20
20  11
22  23
29  15
39  14

つまり、配列は最初の列の値のみを比較して並べ替える必要があります。

Javaには、それを行うための組み込み関数機能があります。以下のように。

Arrays.sort(a, new Comparator<Long[]>() {

            @Override
            public int compare(Long[] o1, Long[] o2) {

                Long t1 = o1[1];
                Long p1 = o1[0];
                Long t2 = o2[1];
                Long p2 = o2[0];

                if (t1 == t2) {
                    return (p1 > p2 ? 1 : (p1 == p2 ? 0 : -1));
                } else {
                    return (t1 < t2 ? -1 : 1);
                }

            }
        });

それで、これらの種類のことを行うためのC++組み込み関数機能はありますか、またはC++(最速の実装)でこれを行うにはどうすればよいですか?

前もって感謝します :)

9
prime

数少ないものの1つだったという理由だけでこれを提供していますstd::qsortwellそのstd::sort単純に、つまり複数列の固定配列をソートしません。コンパレータは3値ステートメントの文字列ですが、十分に長く見つめれば十分に明確である必要があります。

#include <iostream>
#include <random>
#include <algorithm>

int main()
{
    int ar[10][2];

    // populate with random data
    std::random_device rd;
    std::default_random_engine rng(rd());
    std::uniform_int_distribution<> dist(1,20);
    std::for_each(std::begin(ar), std::end(ar),
        [&](int (&ar)[2]){ ar[0] = dist(rng); ar[1] = dist(rng); });

    std::cout << "Before Sort..." << '\n';
    std::for_each(std::begin(ar), std::end(ar),
        [](const int(&ar)[2]) { std::cout << ar[0] << ',' << ar[1] << '\n';});

    std::qsort(ar, 10, sizeof(*ar),
        [](const void *arg1, const void *arg2)->int
        {
            int const *lhs = static_cast<int const*>(arg1);
            int const *rhs = static_cast<int const*>(arg2);
            return (lhs[0] < rhs[0]) ? -1
                :  ((rhs[0] < lhs[0]) ? 1
                :  (lhs[1] < rhs[1] ? -1
                :  ((rhs[1] < lhs[1] ? 1 : 0))));
        });

    std::cout << "After Sort..." << '\n';
    std::for_each(std::begin(ar), std::end(ar),
        [](const int(&ar)[2]) { std::cout << ar[0] << ',' << ar[1] << '\n';});

    return 0;
}

サンプル実行(あなたは明らかに異なります)

Before Sort...
2,11
18,4
20,20
14,6
8,10
17,8
14,14
3,10
20,14
19,19
After Sort...
2,11
3,10
8,10
14,6
14,14
17,8
18,4
19,19
20,14
20,20

注:これは、潜在的なアンダーフローの問題を回避するために、コンパレータで減算ショートカットではなく厳密な値の比較を具体的に使用します。制限されたデータスペースでそれが問題にならない場合は、そのコンパレータを非常に簡単にすることができます。

10
WhozCraig

CおよびC++の組み込み配列は非常に柔軟性がなく、特に割り当てることができません。

最良のオプションは、少なくとも内部次元では、C++標準ライブラリの「配列」クラスです。

_array<int, 2> a[5] = { { 20, 11 },
{ 10, 20 },
{ 39, 14 },
{ 29, 15 },
{ 22, 23 } };

sort( a, a + 5 );
_

編集:もう少し説明。

ここでは、std :: arrayのプロパティを使用します。このプロパティは、デフォルトで「<」が辞書式に比較します。つまり、最初の要素から始まります。物事を異なる方法でソートするには、コンパレータオブジェクトを考え出す必要があるため、2番目の列をソートキーとして使用する場合は、次のようにする必要があります。

_auto comp = []( const array<int, 2>& u, const array<int, 2>& v )
      { return u[1] < v[1]; };
sort( a, a + 5, comp );
_

そして最初のコメントで述べたように、_sort(a, a+5 ..._はクリーナーsort(std::begin(a), std::end(a) ...の醜い短い形式です

7
pentadecagon

可能であれば、Vectorをいくつかの構造体とともに使用して2つのintを保持します。

typedef std::pair<int, int> pairType;
std::vector<pairType> vec;

// Initialize vector

std::sort(std::begin(vec), std::end(vec), [](pairType& first, pairType& second)->bool { return first.first < second.first });
3
MRB

正直なところ、2番目の次元にはintsが2つしかないため、代わりに、独自の比較関数が組み込まれたペアの配列を使用します。 _pair<int,int> arr[200]_のようなものを使用すると、組み込みの並べ替え関数sort(arr, arr + 200)を呼び出すことができます。これにより、配列が最初の要素で並べ替えられ、次に2番目の要素で並べ替えられます。

_#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    // pair of integers
    pair<int, int> arr[1000];

    // fill array with random numbers
    random_device rd;
    mt19937 rng(rd());
    uniform_int_distribution<int> uni(0,1000);
    for(int i = 0; i < 10; i++) {
        // make_pair(x, y) creates a pair with two integers x and y
        arr[i] = make_pair(uni(rng), uni(rng));
    }

    // prints out initial array
    cout << "BEFORE ARRAY..." << endl;
    for(int i = 0; i < 10; i++) {
        // .first and .second call the first and second ints in the pair respectively
        cout << arr[i].first << " " << arr[i].second << endl;
    }
    cout << endl;

    // sort the array by calling built in sort function
    sort(arr, arr + 10);

    // prints out array
    cout << "FINAL ARRAY..." << endl;
    for(int i = 0; i < 10; i++) {
        cout << arr[i].first << " " << arr[i].second << endl;
    }
    cout<<endl;
}
_

このプログラムを実行すると、配列がソートされていることがわかります。

_BEFORE ARRAY...
726 562
916 348
594 6
515 872
976 960
662 169
529 317
789 702
74 255
330 574

FINAL ARRAY...
74 255
330 574
515 872
529 317
594 6
662 169
726 562
789 702
916 348
976 960
_

2番目の要素もどのようにソートされているかに注意してください。ただし、

3
NL628

まず、_vector<vector<int>> array_を指定した場合、これはsort(begin(array), end(array))を使用するだけで並べ替えることができます。これは、vectorが辞書式比較関数を定義しているためです: http://en.cppreference .com/w/cpp/container/vector/operator_cmp

とはいえ、vector- of -vectorsを使用することには欠点があります: vector-of-vectorsの問題は何ですか? そしてそれは明らかに何ではありませんあなたが意図した。 _int array[5][2]_を使用しようとすると sort は次のようになります。

エラーC3863:配列タイプ 'int [2]'は割り当てできません

swapを使用して2 _int[2]_ sを交換する代わりに、sizeof(*array)のバイトを交換する必要があります。これは、 qsortWhozCraigの回答 で示唆されているように、しかし、コンパレータを任意のサイズのサブ配列を処理できるようにすることで改善できます。 _int array[5][2]_または必要な寸法が与えられた場合、次のように記述できます。

_static const auto SIZE = size(*array);   

qsort(array, size(array), sizeof(*array), [](const auto lhs, const auto rhs) {
    const auto first = reinterpret_cast<const int*>(lhs);
    const auto last = next(first, SIZE);
    const auto its = mismatch(first, last, reinterpret_cast<const int*>(rhs));

    if (its.first == last) {
        return 0;
    } else if (*its.first < *its.second) {
        return -1;
    } else {
        return 1;
    }});
_

クイックノートarrayは、標準タイプを定義するため、変数名として使用しないでください。この変更により、ここに例があります: http://ideone.com/87AoIr

2
Jonathan Mee

エンドコンテナが問題にならない場合は、マップを使用してみませんか?

#include<map>

std::map<int, int> m;

for(std::size_t i = 0; i < 5; ++i )
    m[array[i][0]] = array[i][1] ;

これで、marrayにコピーして戻すことができます

std::size_t  i=0;
for(const auto& x:m)
{   
    array[i][0] = x.first ;
    array[i++][1] = x.second ;
}
1
P0W

2D配列を時間内に並べ替える最速の方法(列のみを使用)。 。 。参照の局所性にコストがかかります...それ以外の場合、他のすべての方法では行のコピーが大量に発生します。 。ただし(C++の移動操作はこれを緩和する可能性があります)

2D配列へのポインタの新しい配列を作成します...次に、ポインタを並べ替えます...

そうでなければ、私の前の他のすべての答えは良いようです。ただし、std :: arrayを使用することをお勧めします。

1
WhiZTiM