使用自定义比较功能对静态多维数组进行排序

Sorting static multi dimentional array with custom compare function

本文关键字:数组 排序 静态 自定义 比较 功能      更新时间:2023-10-16

有一些对向量进行排序或动态分配数组的例子,但我找不到任何关于静态数组的帮助。假设我有一个数组

int array[10][10];

和一个比较函数,

bool compare(const int (*a)[10], const int (*b)[10]);

当我这样称呼它时,

std::sort(array, array + 10, compare);

我有编译错误:error: cannot convert 'int*' to 'const int (*)[10]' in argument passing

我尝试了很多方法,在排序函数中将数组转换为(void**),但随后我遇到了分段错误。我的问题是使用数组作为函数参数,但我无法弄清楚如何使用这个 std::sort。否则,我将不得不编写自己的排序函数。

当在

类型为 T 的元素容器上调用 std::sort 时,比较函数需要接收类型 Tconst T& 的参数。在这种情况下,您有一个二维数组,因此元素的类型是一维数组int[10]。由于一维数组衰减为指针,因此compare可以是:

bool compare(int a[10], int b[10]);

或等效:

bool compare(int *a, int *b);

这将修复您遇到的错误,但您的代码仍然不起作用:std::sort需要容器元素可分配(或在 C++11 中可移动),但数组不可分配。

您可以按照人们的建议改用std::vector<std::vector<int> >。请注意,您对性能问题的恐惧是错误的:即使可以对二维数组进行排序,也会涉及大量一维数组的复制,这将需要很长时间。另一方面,交换向量是通过简单地交换指针来完成的,这更快。通常,如果您没有先测试过性能,则不应对性能做出假设。

比较函数不会获得传递给元素的迭代器,而是获取取消引用的迭代器,即值类型。因此,您的比较函数需要声明如下:

bool compare(int (&a0)[10], int (&a1)[10]);

您可以验证是否确实可以使用数组迭代器调用它:

compare(*(std::begin(array) + 0), *(std::begin(array) + 1));

但是,这无法对数组进行排序:内置数组不可复制分配。对静态大小的数组(其中外部维度灵活)进行排序的最简单方法是使用 std::array<T, N>

std::array<int, 10> array[10];
std::sort(std::begin(array), std::end(array));

我说,如果我们要使用STL并C++..让我们用现代风格编写它并真正使用STL。

我尝试使用现代 c++11 解决问题:

#include <vector>
#include <iostream>
#include <algorithm>
typedef std::vector<int> ArrayInt;
typedef std::vector< std::vector<int> > ArrayData;
bool compare(const ArrayInt& a, const ArrayInt& b) {
    std::cout << &(a) << ' ' << &(b) << std::endl;
    int sumA = std::accumulate(a.begin(), a.end(), 0);
    int sumB = std::accumulate(b.begin(), b.end(), 0);
    return sumA < sumB;
}
int main(int argc, char** argv) {
    ArrayData array = {
        {1,2,4,0,3,7,6,8,3,3},
        {13,2,4,0,3,7,6,8,3,3},
        {10,2,4,0,3,7,6,8,3,3},
        {1,2,4,0,3,7,6,8,3,3},
        {16,2,4,0,3,7,6,8,3,3},
        {1,2,400,0,3,7,6,8,3,3},
        {1,2,4,0,3,7,6,8,3,3},
        {120,2,4,0,3,7,6,8,3,3},
        {1,2,4,0,3,7,6,8,3,3},
        {1,2,4,0,3,7,6,8,3,3}
    };
    std::sort(array.begin(), array.end(), compare);
    for (auto row : array) {
        for (int num : row)
            std::cout << num << ' ';
        std::cout << std::endl;
    }
}

它使用累加对每个子数组求和,并对总和进行排序......效率非常低,因为它必须多次对同一行求和......但它只是为了炫耀自定义比较函数。


作为练习,我编写了这个版本,它使用异步将求和部分分布在任何可用内核上,以便在排序之前进行求和。很抱歉有点跑题了。我希望它对某些人仍然有用:

#include <vector>
#include <iostream>
#include <algorithm>
#include <future>
typedef std::vector<int> IntRow;
typedef std::pair<int, IntRow> DataRow;
typedef std::vector<DataRow> DataTable;
int main(int argc, char** argv) {
    // Holds the sum of each row, plus the data itself
    DataTable array = {
        {0, {1,2,4,0,3,7,6,8,3,3}},
        {0, {13,2,4,0,3,7,6,8,3,3}},
        {0, {10,2,4,0,3,7,6,8,3,3}},
        {0, {1,2,4,0,3,7,6,8,3,3}},
        {0, {16,2,4,0,3,7,6,8,3,3}},
        {0, {1,2,400,0,3,7,6,8,3,3}},
        {0, {1,2,4,0,3,7,6,8,3,3}},
        {0, {120,2,4,0,3,7,6,8,3,3}},
        {0, {1,2,4,0,3,7,6,8,3,3}},
        {0, {1,2,4,0,3,7,6,8,3,3}}
    };
    // Make use of multiple cores if it's efficient enough
    // get the sum of each data row
    std::vector<std::future<int>> sums(array.size());
    auto next = sums.begin();
    for (auto& row : array)
        *next++ = std::async([](const IntRow& row) { return std::accumulate(row.begin(), row.end(), 0); }, row.second);
    // Get the results
    auto nextRow = array.begin();
    for (auto& sum: sums)
        (*nextRow++).first = sum.get();
    // Sort it 
    std::sort(array.begin(), array.end(),
              [](const DataRow& a, const DataRow& b) { return a.first < b.first; });
    // Print it
    for (auto row : array) {
        for (int num : row.second)
            std::cout << num << ' ';
        std::cout << std::endl;
    }
}

它需要使用 pthread 库或类似的东西进行编译:

g++ -O6 sort.cpp --std=c++11 -g -lpthread