【问题标题】:std::sort to sort an array and a list of index?std::sort 对数组和索引列表进行排序?
【发布时间】:2012-11-28 16:28:23
【问题描述】:

我有一个函数,它接受两个大小相同的向量作为参数:

void mysort(std::vector<double>& data, std::vector<unsigned int>& index)
{
   // For example :
   // The data vector contains : 9.8 1.2 10.5 -4.3
   // The index vector contains : 0 1 2 3
   // The goal is to obtain for the data : -4.3 1.2 9.8 10.5
   // The goal is to obtain for the index : 3 1 0 2
   // Using std::sort and minimizing copies
}

如何解决这个问题,尽量减少所需副本的数量?

一种明显的方法是制作std::pair&lt;double, unsigned int&gt; 的单个向量并通过[](std::pair&lt;double, unsigned int&gt; x, std::pair&lt;double, unsigned int&gt; y){return x.first &lt; y.first;} 指定比较器,然后将结果复制到两个原始向量中,但效率不高。

注意:函数的签名是固定的,我不能传递std::pair的单个向量。

【问题讨论】:

  • 副本不是更容易编写,而且时间复杂度更高。
  • 我不知道为什么你会想要一个不再包含对现在排序数组的有效偏移量的索引。是否只是为了知道元素在排序之前 位于哪些插槽中?
  • @WhozCraig:这被称为“从排列”。这种情况下的问题是对值进行排序,并为排序后的数组生成一个“从排列”,即 original 索引数组。这是一个很常见的问题。
  • index 保证是[0,1,2,...],或者这只是一个例子?

标签: c++ algorithm sorting c++11


【解决方案1】:

在函数内部,做一个向量positions = [0,1,2,3...] 使用比较器(int x, int y){return data[x]&lt;data[y];} 对位置进行排序。

然后遍历位置,做result.push_back(index[*it]);

这假定index 中的值可以是任意的。如果在您的示例中保证它已经是 [0,1,2..],那么您不要创建 positions 数组,只需在其位置使用 index 并跳过最后一个副本。

【讨论】:

    【解决方案2】:

    http://www.boost.org/doc/libs/1_52_0/libs/iterator/doc/index.html#iterator-facade-and-adaptor

    std::pair&lt;double&amp;, signed int&amp;&gt; 上编写一个迭代器,它实际上将一对迭代器包装到每个向量中。唯一棘手的部分是确保std::sort 意识到结果是随机访问迭代器。

    如果你不能使用 boost,就自己写一个等价的。

    在执行此操作之前,请确定是否值得您费心。 zip、sort 和 unzip 更容易编写,并且程序员的时间可以在很多地方换取性能:直到你知道它的最佳使用位置,也许你应该做一个足够好的工作,然后在你需要的地方进行基准测试加快速度。

    【讨论】:

      【解决方案3】:

      您可以使用自定义迭代器类,它并行迭代两个向量。其内部成员将包括

      1. 两个引用(或指针),每个向量一个
      2. 指示当前位置的索引

      迭代器的值类型应该是pair&lt;double, unsigned&gt;。这是因为std::sort 不仅会交换项目,而且在某些情况下还会临时存储单个值。我在this question 的第 3 节中写了更多详细信息。

      引用类型必须是某个类,它再次保存对向量和当前索引的引用。因此,如果您小心的话,您可以使引用类型与迭代器类型相同。引用类型的operator= 必须允许从值类型进行赋值。并且 swap 函数应该专门用于此引用,以允许通过分别交换两个列表来就地交换此类列表项。

      【讨论】:

        【解决方案4】:

        您可以使用仿函数类来保存对值数组的引用,并将其用作比较器来对索引数组进行排序。然后将值复制到一个新的值数组并交换内容。

        struct Comparator
        {
            Comparator(const std::vector<double> & data) : m_data(data) {}
            bool operator()(int left, int right) const { return data[left] < data[right]; }
            const std::vector<double> & m_data;
        };
        
        void mysort(std::vector<double>& data, std::vector<unsigned int>& index)
        {
            std::sort(index.begin(), index.end(), Comparator(data));
            std::vector<double> result;
            result.reserve(data.size());
            for (std::vector<int>::iterator it = index.begin(), e = index.end();  it != e;  ++it)
                result.push_back(data[*it]);
            data.swap(result);
        }
        

        【讨论】:

        • 我会将构造函数的参数设为 const 引用,并将 operator() 设为 const 成员函数。
        • (关于删除 const 引用参数的别名的评论)没关系,这对这个问题并不重要/无关。
        【解决方案5】:

        应该这样做:

        std::sort(index.begin(), index.end(), [&data](unsigned i1, unsigned i2)->bool
        { return data[i1]<data[i2]; });
        
        std::sort(data.begin(), data.end());
        

        【讨论】:

          猜你喜欢
          • 2018-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-26
          • 2016-11-20
          • 2012-11-03
          相关资源
          最近更新 更多