【问题标题】:Sort a matrix defined as a vector<double>对定义为 vector<double> 的矩阵进行排序
【发布时间】:2017-03-16 19:54:51
【问题描述】:

假设我有一个大小为n 的方阵A,定义为std::vector&lt;double&gt;

std::vector<double> A(n*n);

矩阵的元素按通常的方式访问:

double a_ij = A[i*n + j];

我需要相对于第一列按升序对矩阵的行进行排序。

qsort 函数允许我使用数组和函数指针来完成此操作,但我想找到一种方法来使用向量和std::sort 来完成此操作。

另外,请注意,出于性能原因,我不希望将我的矩阵定义为向量向量。

编辑:

我传递给 qsort 的函数:

static int comparisonFunction(const void* firstRow, const void* secondRow) 
{
    if (((double *)firstRow)[0] < ((double *)secondRow)[0]) return -1;
    else if (((double *)secondRow)[0] < ((double *)firstRow)[0]) return 1;
    return 0;
}

还有电话:

std::qsort(matrixArray, nbRows, sizeof(double)*nbRows, comparisonFunction);

【问题讨论】:

  • 能否详细说明“性能原因”?
  • 我需要对排序后的矩阵进行大量计算,因此内存连续性更可取。
  • 你需要一个包装器来允许beginend遍历行
  • @doctorlove :我添加了一些关于如何让 qsort 工作的精确度。
  • 我可能会分两步完成。对包含每行的第一个条目和原始索引的对向量进行排序,然后使用其结果重新排列矩阵。对向量进行排序很快,您可以在排序过程中节省移动整行。

标签: c++ sorting stl qsort


【解决方案1】:

std::sort 在迭代器上工作,并不关心迭代器的实现。因此,如果你定义了一个struct RowIter,它包装了一个std::vector&lt;double&gt;&amp; matrix,其中一个成员size_t RowSize代表operator+(size_t)(和operator-operator++等)和一个Row operator*() const,那么std::sort可以排序那个迭代器。

不幸的是,仍然比qsort 做了大量工作,但它可以推广到非 POD 类型。

【讨论】:

  • RowIter 是否应该从 RandomAccessIterator 继承?
  • @Dooggy:不是继承,但它确实应该实现整个 RandomAccessIterator 概念。固定。
  • @Dooggy:由于您是新手,可能会将 StackOverflow 与论坛混淆,因此我们试图将其保留为问答网站。非常感谢您提供最终解决方案,但您可以将其作为答案。 (没有刻意回答你自己的问题的规则)
【解决方案2】:

可以将qsort 替换为std::sort 以对底层数组进行排序,但您必须定义:

  • 一种直接访问向量底层存储的 Row 类型 - 您不能在此处使用向量,因为即使一个或多个数组仍然是一个数组,向量的向量也不是正方形大小的向量。更糟糕的是,我不知道将现有存储分配给向量的可移植方法。该 Row 类型必须是可移动构造和可移动分配的,并且正确支持交换。
  • 该 Row 类型上的 RandomAccessIterator,能够正确处理底层数组的末尾。

这取决于你,但标准 C++ 的所有版本都明确支持 C 库,所以在这个用例中使用 qsort 并没有什么坏处,因为它更简单,最终错误更少-易于。 qsort 方式只需要 7 行,易于控制和同行评审。 nice C++ 方式将需要至少 2 个具有非平凡构造函数的类,因此需要更多的行和更多错误的可能性。

如果你真的不能使用qsort,可能是为了内部编码规则,那么我只需将数据复制到向量向量中,对其进行排序并将数据复制回初始向量。它涉及矩阵的 2 个额外完整副本,但至少使用标准类并且需要的编码要少得多。

【讨论】:

    【解决方案3】:

    最简单的解决方案是保留qsort() 并只使用std::vector::data(),它返回一个指向第一个元素的指针,从而允许您使用std::vector 与C 数组非常相似:

    std::qsort(matrixArray.data(), nbRows, sizeof(double)*nbRows, comparisonFunction);
    

    正确使用std::sort() 是可能的,但很冗长,因为您不仅需要一个随机访问迭代器类来逐行迭代,还需要一个抽象行以便std::sort() 可以交换它们的类。

    一种解决方法,但仍使用std::sort 是将要排序的元素与索引一起提取到它们自己的std::vector 中。然后对该向量进行排序,最后根据该向量中的索引对原始矩阵中的行进行重新排序。

    #include <vector>
    #include <tuple>
    #include <algorithm>
    
    const int n = 10;
    
    std::vector<double>
    row_sort(std::vector<double> const& A)
    {
      std::vector<std::tuple<int, double> > first_element(n);
      for(int i = 0; i < n; ++i)
      {
        first_element[i] = std::make_tuple(i, A[i*n]);
      }
    
      std::sort(std::begin(first_element), std::end(first_element),
                [](std::tuple<int, double> const& lhs,
                   std::tuple<int, double> const& rhs)
                {
                  return std::get<1>(lhs) < std::get<1>(rhs);
                });
    
      std::vector<double> result(n*n);
      for(int i = 0; i < n; ++i)
      {
        std::copy_n(&A[std::get<0>(first_element[i])*n], n, &result[i*n]);
      }
    
      return result;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      相关资源
      最近更新 更多