【问题标题】:Sort 2 dimensional c array with std::sort使用 std::sort 对二维 c 数组进行排序
【发布时间】:2018-09-15 17:31:28
【问题描述】:

我似乎无法使用 std::sort 对二维 c 数组进行排序。但是,我可以对一维数组进行排序。这是在我在 c++ 程序中收到一个 c 数组并希望在不将其复制到 std::array 的情况下进行排序的情况。也许有一些方法可以将它变成一个 std::array 而不复制它?这对我来说听起来很可疑,因为任何 std::array 都会在它不拥有的内存上调用析构函数。

排序一维 c 样式数组工作得很好:

int len = 5;
auto one_dim_less = [](int a, int b){
  return a < b;
};
int one_dim[] = {4, 0, 3, 1, 2};
std::sort(one_dim, one_dim + len, one_dim_less);

尝试按第二个数字对二维 c 样式数组进行排序无法编译:

int len = 5;
auto two_dim_less = [](int a[2], int b[2]){
  return a[1] < b[1];
};
int two_dim[][2] = {{1,8}, {2,4}, {3,10}, {4,40}, {5,1}};
std::sort(two_dim, two_dim + len, two_dim_less);

【问题讨论】:

  • 问题是不能赋值C数组,比如two_dim[0] = two_dim[1]无效。
  • 与排序相比,复制整个数组所需的时间可以忽略不计,因此是否复制可能并不重要。请注意,如果行很长(不仅仅是像这里那样大小为 2),那么对侧面的键进行排序并在最后将最终排列应用于矩阵可能会更有效,以避免每次排序交换时复制整行 2元素。
  • @MarcGlisse 您对复制数组的时间提出了一个很好的观点。我希望我的服务需要 O(1) 空间,但在我制作完整副本时并非如此。另外,关于嵌套数组的内容。
  • 注意:std::sort 不能保证就地排序。 (通常使用 introsort 实现,但如果使用插入排序,它可能会allocate memory for one additional element

标签: c++ arrays sorting stl


【解决方案1】:

也许有一些方法可以将其变成std::array 而无需复制 是吗?

可能不会变成std::array 本身,但另一种方法可能是将2D C 样式数组转换std::array 参考只是为了排序。这样做依赖于标准,即内存中的std::array 表示至少从其 C 样式数组 等效项开始。请参阅[array.overview§2] 下的此处:

数组是一个聚合,最多可以用 N 进行列表初始化 类型可转换为 T 的元素。

在实践中,reinterpret_cast 的以下用法很可能是安全的,但请注意,除非在标准中的某处有特殊例外,否则它将正式成为未定义的行为:

#include <algorithm>
#include <array>
#include <iostream>

int main() {
  auto two_dim_less = [](std::array<int, 2>& a, std::array<int, 2>& b) {
      return a[1] < b[1]; };

  int two_dim[][2] = {{1, 8}, {2, 4}, {3, 10}, {4, 40}, {5, 1}};

  std::array<std::array<int, 2>, 5>& arr =
    *reinterpret_cast<std::array<std::array<int, 2>, 5>*>(&two_dim);

  std::sort(arr.begin(), arr.end(), two_dim_less);

  for (int i = 0; i < 5; i++)
    std::cout << two_dim[i][0] << ", " << two_dim[i][1] << '\n';

  return 0;
}

输出:

5, 1
2, 4
1, 8
3, 10
4, 40

关于std::qsort() 的使用,请注意it is potentially slower than std::sort() 由于后者允许内联比较而前者不允许。

【讨论】:

  • 一个很好的答案!我使用的唯一问题是我正在使用的函数传递了任意长度的数组以及一个长度变量,并且 std::array 在编译时必须具有长度。我不认为这种方法可以解决这个问题,但这确实教会了我一些东西。
  • 我想了想,意识到我可以将你的方法用于采用任何大小 c 数组的函数,如下所示:auto&amp; arrr = *reinterpret_cast&lt;std::array&lt;int, 2&gt; **&gt;(&amp;arr2); std::sort(arrr, arrr + rows, two_dim_less);
【解决方案2】:

std::sort()requires 用于排序的对象 MoveAssginable

数组不是 MoveAssginable(也不是可赋值的)。

尝试使用结构数组或std::pairs。

【讨论】:

  • 谢谢。除非我愿意将其复制到我自己的结构中,否则我无法更改输入。这有助于澄清为什么我无法编译它,并且我要么需要付出复制的代价,要么定义我自己的排序函数。
  • 看起来 std::qsort 不需要这个。这行得通吗?
  • @Peter 是的,qsort 应该可以工作,因为它直接移动字节,而不是依赖于operator=。但请注意,如果它使用的对象不是trivially copyable,它将导致未定义的行为。 ints 和 ints 的数组 可以简单地复制,但大多数类(如 std::strings)不能。在实践中,您可能可以使用qsorting 大多数类(除非它们例如依赖operator= 来更新一些指向其位置的外部指针),但您仍应谨慎使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 2011-08-19
  • 1970-01-01
相关资源
最近更新 更多