【问题标题】:Sorting a vector of (double precision) reals and obtain their对(双精度)实数向量进行排序并获得它们的
【发布时间】:2011-05-30 05:20:30
【问题描述】:

在 C++ 中想要对一个冗长的 (2^20) 实数向量进行排序,显然 sort() 可以解决问题。在我习惯了漂亮的order() 函数之前使用过 R,它会产生导致排序向量的排列。

例子:

x = {24, 55, 22, 1}

然后排列

perm = {3, 2, 0, 1}

将原始x 映射到按升序排序的x

我可能可以实现一些冒泡排序,它不仅对 x 进行排序,而且对向量 {0,1,2,...} 执行相同的转置并输出两者,但我相信一定有人考虑过,尤其是高效地完成了它。

【问题讨论】:

    标签: c++ sorting vector permutation


    【解决方案1】:

    我会说最好的方法是创建一个整数 0..N 的向量,然后使用比较函数对该数组进行排序,该函数比较您尝试查找排序排列的向量的相应元素。比如:

    #include <vector>
    #include <algorithm>
    
    template<class T> class sorter {
        const std::vector<T> &values;
    public:
        sorter(const std::vector<T> &v) : values(v) {}
        bool operator()(int a, int b) { return values[a] < values[b]; }
    };
    
    template<class T> std::vector<int> order(const std::vector<T> &values)
    {
        std::vector<int> rv(values.size());
        int idx = 0;
        for (std::vector<int>::iterator i = rv.begin(); i != rv.end(); i++)
            *i = idx++;
        std::sort(rv.begin(), rv.end(), sorter<T>(values));
        return rv;
    }
    

    这最大限度地减少了分配开销,因为我们不创建任何我们排序然后提取最终排列的大型临时对象——返回的相同向量是排序的临时对象。

    【讨论】:

    • 我喜欢你的方法,但它不会编译。你应该纠正它。这里有一点更正的代码,仍然无法编译,但我没有时间:ideone.com/hM8SC
    • @Pawel:某些版本的 gcc 有问题,不喜欢模板函数中的局部类声明,然后将其传递给其他模板函数,因此我将其拆分以避免该问题。
    • 这段代码编译成功——尽管我注意到这篇文章是在你发表评论后编辑的。
    • @DeadMG:原始代码(在修复了琐碎的错别字之后——缺少;)将使用 gcc 4.5 -std=c++0x 进行编译。上面修改后的代码也可以用 gcc 4.4 编译
    • 在 C++0x 中,您可以使用 lambda 函数,而不是仿函数对象(查看我编辑的答案)。代码更短,IMO 更简洁。
    【解决方案2】:

    您可以使用std::sort 对 {(24, 0), (55, 2), (22, 0), (1, 1)} 对列表进行排序。它不是特别漂亮,但我通常会这样做:

    #include <vector>
    #include <algorithm>
    #include <utility>
    
    typedef std::pair<double, int> Pair;
    
    struct CmpPair
    {
        bool operator()(const Pair& a, const Pair& b)
        { return a.first < b.first; }
    };
    
    void sortingPermutation(
        const std::vector<double>& values,
        std::vector<int>& permutation)
    {
        std::vector<Pair> pairs;
        for (int i = 0; i < (int)values.size(); i++)
            pairs.push_back(Pair(values[i], i));
    
        std::sort(pairs.begin(), pairs.end(), CmpPair());
    
        typedef std::vector<Pair>::const_iterator I;
        for (I p = pairs.begin(); p != pairs.end(); ++p)
            permutation.push_back(p->second);
    }
    

    这是测试:

    #include <iostream>
    
    int main()
    {
        std::vector<double> values;
        values.push_back(24);
        values.push_back(55);
        values.push_back(22);
        values.push_back(1);
    
        std::vector<int> permutation;
        sortingPermutation(values, permutation);
    
        typedef std::vector<int>::const_iterator I;
        for (I p = permutation.begin(); p != permutation.end(); ++p)
            std::cout << *p << " ";
        std::cout << "\n";
    }
    

    【讨论】:

    • 干得好。此外,使这个模板不仅能够对双打进行排序也会很棒。当然,在向量上调用 reserve 会减少对 new/malloc 的调用次数,从而为您节省大量时间。
    【解决方案3】:

    编辑

    不使用辅助向量的方法比以前更好:(source on ideone):

    #include <vector>
    #include <algorithm>
    #include <iostream>
    
    template<class Vals>
    void sortingPermutation(const Vals& values, std::vector<int>& v){
      int size = values.size(); 
      v.clear(); v.reserve(size);
      for(int i=0; i < size; ++i)
        v.push_back(i);
    
      std::sort(v.begin(), v.end(), [&values](int a, int b) -> bool { 
        return values[a] < values[b];
      });
    }
    
    int main()
    {
        std::vector<double> values;
        values.push_back(24);
        values.push_back(55);
        values.push_back(22);
        values.push_back(1);
    
        std::vector<int> permutation;
        sortingPermutation(values, permutation);
    
        typedef std::vector<int>::const_iterator I;
        for (I p = permutation.begin(); p != permutation.end(); ++p)
            std::cout << *p << " ";
        std::cout << "\n";
    }
    

    我使用的是 C++0x 中的 lambda,但可以用简单的仿函数对象替换它:

    template<class T>
    struct CmpPairs{
      CmpPairs(const std::vector<T> &v): v_(v) {}
      std::vector<T> v_;
      bool operator()(int a, int b){ return v_[a] < v_[b]; }
    };
    
    template<class T>
    CmpPairs<T> CreateCmpPairs(const std::vector<T> & v) { return CmpPairs<T>(v); }
    //in sortingPermutation:
    std::sort(v.begin(), v.end(), CreateCmpPairs(values));
    

    std::map的旧解决方案来源:ideone

    【讨论】:

    • 我看到的经验法则是,对向量进行排序比使用自排序容器更有效。从未测试过它的真实性。
    • 使用 C++0x(lambda 可以用仿函数替换)更好:ideone.com/wRHYv 我认为比 antonakos'es 好得多,因为没有辅助对象只是为了排序。
    猜你喜欢
    • 2016-11-22
    • 2013-10-03
    • 2022-01-24
    • 2011-12-30
    • 1970-01-01
    • 2010-10-22
    • 2016-08-24
    • 1970-01-01
    相关资源
    最近更新 更多