【问题标题】:Sort a 2D array in C++ using built in functions(or any other method)?使用内置函数(或任何其他方法)在 C++ 中对二维数组进行排序?
【发布时间】:2014-01-22 18:38:40
【问题描述】:

我有一个如下所示的二维数组。 (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++ 中做到这一点(最快的实现)?

提前谢谢:)

【问题讨论】:

  • 你是如何声明数组[5][2]的。它们只是 int 还是您使用了像 std::vector、std::array 等 STL 容器?
  • 听起来很奇怪,std::qsort() 在按单列排序时可能更容易嵌入到经典的二维数组中。
  • std::sort 接受比较器作为第三个参数。任何op 使得op(a,b) 表示a &lt; b 都可以——函数、lambda、函子对象。由于内联,它通常也比具有相同功能的qsort 更快。
  • 我已经看到了解决方案,它们都将问题转化为解决问题 (std::array, std::vector, std::map) 。有没有办法用二维数组排序?毕竟,指针可以是迭代器。临时我没有看到解决方案,因为最里面的维度是一个数组并且数组是不可分配的。嵌入在结构中的数组是。

标签: c++ arrays sorting


【解决方案1】:

我提供这个只是因为它是 std::qsort 所做的少数事情之一 很好 而 std::sort 根本不这样做,即对多列固定数组进行排序:比较器是一串三元语句,但如果你盯着它看足够长的时间应该足够清楚:

#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

注意:这专门使用严格值比较而不是比较器中的减法快捷方式,以避免潜在的下溢问题。如果在您受限的数据空间中这不是​​问题,您可以轻松地使比较器变得更简单。

【讨论】:

  • 为什么VS下的代码会把error C2664: 'qsort' : cannot convert parameter 4 from 'anonymous-namespace'::'给'int (__cdecl *)(const void *,const void *)'`?
  • 为什么你认为std::sort(std::begin(ar), std::end(ar), [](int const (&amp;ar)[2])-&gt;bool{…} 不能正常工作?
  • @ChristopherCreutzig 您尝试过吗? std::sort 使用移动和赋值,固定的 C 数组不能按值赋值(尽管它们可以被初始化)。所以回答你提出的问题,因为它根本不起作用,因此它也不起作用。
  • @herohuyongtao 那将是 MS 的错,但是您可以通过将 lambda 移动到它自己的静态函数来解决它。其余的都是一样的。
  • @WhozCraig 我的 iPad 上没有 C++,抱歉。 :-) 当然,你是对的——虽然固定的 C 数组具有我们知道它们的布局(在所有实际情况下)的次要优势,但它们在 C++ 世界中的行为并不正常.并且对于任何半体面的编译器,一个简单的std::pair&lt;int,int&gt; 或没有虚拟的自定义类也不会占用更多空间,所以一开始就没有理由使用它们。
【解决方案2】:

C 和 C++ 的内置数组非常不灵活,其中不能赋值。

您最好的选择是 C++ 标准库中的“数组”类,至少对于内部维度而言:

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

sort( a, a + 5 );

编辑:更多解释。

这里我们使用 std::array 的属性,默认情况下 '

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) ... 的一个丑陋的简短形式@

【讨论】:

  • 使用std::begin(a)和std::end(a)代替a和a + 5。
  • 根据第二个元素排序怎么样?
  • @herohuyongtao: sort( a, a + 5, []( array&lt;int, 2&gt;&amp; u, array&lt;int, 2&gt;&amp; v ){ return u[1] &lt; v[1]; } );
【解决方案3】:

老实说,由于您的第二维中只有两个 ints,因此我会使用一对数组来代替,它们有自己的内置比较函数。使用pair&lt;int,int&gt; arr[200] 之类的东西,您将能够调用内置的排序函数sort(arr, arr + 200),它会按第一个元素对数组进行排序,然后再按第二个元素排序。

#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

注意第二个元素也是如何排序的,但次要于

【讨论】:

    【解决方案4】:

    首先,如果你给了vector&lt;vector&lt;int&gt;&gt; array,这将可以使用:sort(begin(array), end(array)) 进行排序,因为vector 定义了字典比较函数:http://en.cppreference.com/w/cpp/container/vector/operator_cmp

    也就是说,使用 vector-of-vectors: What are the Issues with a vector-of-vectors? 有一些缺点,这显然不是您想要的。鉴于 int array[5][2] 尝试使用 sort 将产生:

    错误 C3863:数组类型“int [2]”不可分配

    我们只需要交换 sizeof(*array) 的字节,而不是使用 swap 交换 2 个 int[2]s,这可以按照 WhozCraig's answer 的建议使用 qsort 来完成,但我们可以对此进行改进使我们的比较器能够处理任何大小的子阵列。给定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

    【讨论】:

    • 不错的答案。请注意,向量向量的大多数缺点在 OP 的 C++11 及更高版本的固定数组的特定情况下消失了。事实上,std::array&lt;std::array&lt;int, M&gt;, N&gt; 和 N 和 M 分别是行和列,与 std::sort 一起工作得很好。如果外部维度可能不规则,数组向量仍然可以正常工作。
    • @WhozCraig 读了你的答案后,我花了 2 年时间写它;)
    【解决方案5】:

    如果可以的话,使用Vector 和一些结构来保存两个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 });
    

    【讨论】:

      【解决方案6】:

      如果结束容器无关紧要,使用地图怎么样?

      #include<map>
      
      std::map<int, int> m;
      
      for(std::size_t i = 0; i < 5; ++i )
          m[array[i][0]] = array[i][1] ;
      

      您现在可以将m 复制回您的array

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

      【讨论】:

      • 只是要指出,这仅在 array[i][0] 是唯一的情况下才有效(对于所有 i)。
      【解决方案7】:

      及时对二维数组进行排序的最快方法(仅使用列)。 . .将花费您参考位置...否则,其他所有方式都将涉及大量复制行...。 .虽然(C++ 的移动操作可能会缓冲这一点)

      您将创建一个指向二维数组的新指针数组...然后对指针进行排序...

      否则,我之前的所有其他答案似乎都不错。但我建议你使用 std::array。

      【讨论】:

        【解决方案8】:

        我们可以使用 C++ 中的内置排序功能简单地使用基于行或列的排序。 我们只需要传递带有适当参数的比较函数。

        这是一个按列排序二维数组的示例。

        #include<iostream>
        #include<algorithm>
        using namespace std;
        
        bool compare(int *a, int *b){
            // sorting on basis of 2nd column
            return a[1] < b[1];
        }
        
        void sorting(int **arr,int n){
            //calling in built sort
            sort(arr, arr + n, compare);
            // printing after sorting 
            cout<<"---------After Sorting---------"<<endl;
            for(int i = 0; i < n; i++){
                cout<<arr[i][0]<<" "<<arr[i][1]<<endl;
            }
        }
        
        int main(){
            int **arr, i, n;
            cout<<"Enter the size of array  : ";
            cin>>n;
            //array of size arr[n][2]; 
            arr = new int*[n];
            for(i = 0; i < n; i++){
                arr[i] = new int[2];
            }
            
            for(int i = 0; i < n; i++){
                cin>>arr[i][0];
                cin>>arr[i][1];
            }
            
            sorting(arr, n);
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-17
          • 2015-01-30
          • 2012-12-15
          相关资源
          最近更新 更多