【问题标题】:c++ vector two sided sortingc++ 向量两侧排序
【发布时间】:2013-08-22 05:23:28
【问题描述】:

我有一个包含字符串和整数(计数)对的向量,我根据计数对所有内容进行了排序,但如果列表中有 2 个或更多重复项,我还必须对字符串进行排序。例如;

3 试用 2 好吃 2 abc

所以,列表中有 2 个 2,因此 abc 必须在 yummy 之前。我的代码如下所示:

vector<pair<string, int> > values(hash_table.begin(), hash_table.end());

sort(values.begin(), values.end(), sort_reverse);


bool sort_reverse(const pair<string, int> &a, const pair<string, int> &b) {
  return a.second > b.second;
}

【问题讨论】:

    标签: c++ sorting


    【解决方案1】:

    您可以通过使用大于比较而不是默认的小于来反转任何范围的排序:

    std::sort(values.begin(), values.end(), std::greater<std::pair<string, int>>());
    

    或者,您可以颠倒迭代顺序:

    std::sort(values.rbegin(), values.rend());
    

    编辑 如果您想更改比较标准,首先按对的second 进行字典比较,然后是first,您可以提供自己的比较功能。它仍必须满足strict weak ordering 的要求,如上例所示。使用std::tie 实现字典比较很简单:

    #include <tuple>
    
    template<typename T1, typename T2>
    struct pair_backwards_greater
    {
      bool operator()(const std::pair<T1, T2>& lhs, const std::pair<T1, T2>& rhs) const
      {
        return std::tie(lhs.second, lhs.first) > std::tie(rhs.second, rhs.first);
      }
    };
    

    然后

    std::sort(values.begin(), values.end(), pair_backwards_greater<string, int>());
    

    您还可以选择使用简单的 lambda 表达式,而不是手动编写仿函数:

      std::sort(values.begin(), values.end(),
                [](const std::pair<std::string, int> &lhs, const std::pair<std::string, int> &rhs) 
                {
                  return std::tie(lhs.second, lhs.first) > std::tie(rhs.second, rhs.first); 
                }  
               );
    

    std::tie 需要 C++11 库支持,但在 boost::tiestd::tr1::tie 中有 C++03 替代实现。 Lambda 表达式需要 C++11 语言支持。

    【讨论】:

    • +1 或rbegin()rend() 只是为了看看班级评分员是否在关注。
    • 对不起,我没明白你的意思。实际上,我正在根据元素的数量对元素进行排序。如果有 2 个或更多元素具有相同的计数,我只想对字符串进行排序。因此,在这种情况下,您的解决方案并不能真正解决我的问题。
    • @Jason “他们的人数”是什么?据我了解,这可以解决问题。
    • 所以有2对。对 1->“test”的计数为 2,对 2->“asd”的计数为 2。首先我是根据它们的计数来比较它们,但现在我必须根据它们的计数和字母顺序来比较它们.
    • @Jason 啊好的,所以你想通过int第一和string第二比较它们?我将编辑我的答案。
    【解决方案2】:

    一次性对两个字段进行排序:

    bool sort_pair(const std::pair<std::string, int> &a, const std::pair<std::string, int> &b) 
    {
        return (a.second > b.second) ||  
            ( 
                (a.second == b.second)  &&
                (a.first > b.first)
        );
    }
    
    void sortVector(std::vector<std::pair<std::string, int> >& values)
    {
        std::sort(values.begin(), values.end(), sort_pair);
    }
    

    另见existing 条目

    【讨论】:

    • 是的,我只是在寻找这个:D
    • @P0W 完全正确;实际上,pair 的排序是规范的,只有通常主排序基于 first 而不是 second
    【解决方案3】:

    你必须考虑价值观本身。

    bool sort_reverse(const pair<string, int> &a, const pair<string, int> &b) {
        return (a.second > b.second) || ((a.second == b.second) && (a.first > b.first));
    }
    

    【讨论】:

    • 为什么会这样?他正在搜索类似 1 的排序:“3 trail” 2:“2 abc”(前导 'a' 的 2 个输入原因) 3:“2 yummy”(前导 'y' 的 3 个输入原因)
    • 感谢您再次投票;)我真的不知道为什么它被否决了...没有评论:P @Jason:np,yw
    • 因为它不满足严格的弱排序,这是排序算法的要求。这是技术上未定义的行为。
    • 不起作用;正如@juanchopanza 所说,这将在某些数据上完全失败。
    • 你能举个例子吗?我不知道这会在哪里失败?它是更大还是不是更大......如果第二个不是更大,那无论如何都是错误的,如果第二个更大,它取决于第一个可能更大与否......
    【解决方案4】:

    我想提出一个替代方案,略有不同,并介绍stable_sort的好处。

    typedef std::pair<int, std::string> CNP;
    
    bool byName(CNP const& left, CNP const& right) { return left.second < right.second; }
    bool byCount(CNP const& left, CNP const& right) { return left.first < right.first; }
    
    std::sort(values.begin(), values.end(), byName);
    
    std::stable_sort(values.begin(), values.end(), byCount);
    

    这是因为在等价元素(比较相等的元素)的情况下,stable_sort 保留它们的相对顺序(sort 可以,但不保证)。

    因此,假设你有[ (3, "apple"), (2, "zorro"), (2, "banana") ]

    • 按名称排序产生:[ (3, "apple"), (2, "banana"), (2, "zorro") ]
    • 按计数稳定排序:[ (2, "banana"), (2, "zorro"), (3, "apple") ]

    如果您不需要中间步骤,那么使用单个排序和更复杂的谓词当然会更有效;但是,如果您收到已按名称排序的列表,则仅按计数应用 stable_sort 可能会更快。

    最后,一个简单的技巧来检查列表是否按照标准排序:

    template <typename C, typename P>
    bool is_sorted(C const& list, P comp) {
        typedef typename C::const_reference CR;
    
        auto const reversed = [](CR left, CR right) { return comp(right, left);  };
    
        return std::adjacent_find(list.begin(), list.end(), reversed) == list.end();
    }
    

    注意:C++11 有一个is_sorted 方法,虽然用迭代器表示,当然不是容器。

    【讨论】:

    • 这是一个非常有用的建议。 BTW 值得一提的是,C++11 中有一个std::is_sorted
    • @juanchopanza:哦!我不知道!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 2015-09-06
    • 2019-03-16
    • 2011-10-30
    相关资源
    最近更新 更多