【问题标题】:How to sort std::set according to the second element?如何根据第二个元素对 std::set 进行排序?
【发布时间】:2019-07-15 11:51:49
【问题描述】:

给定二维空间中的n点,按升序顺序对所有点进行排序。

(x1,y1) > (x2,y2) if and only if (x1>x2) or (x1==x2 && y1<y2)

输入规范

第一行包含一个整数t,即测试用例的数量。然后对于每个测试用例,第一行包含一个整数n,即点数。然后接下来的n 行包含两个整数xiyi,它们代表点。

输出规范

对于每个测试用例,打印点的排序顺序。 输入约束:

1 <= t <= 10
1 <= n <= 100000
- 10 ^ 9 <= co - ordinates <= 10 ^ 9

注意:严格的时间限制。首选scanf/printf/BufferedReader 而不是cin/cout/Scanner

示例输入

1
5
3 4
-1 2
5 -3
3 3
-1 -2

样本输出

-1 2
-1 -2
3 4
3 3
5 -3

我声明了一个set,现在我想在键相等时按降序(值)排序。这是我的代码:

int main() 
{
    int n, i, hold = 0;
    set<pair<int, int>>s;
    int x, y, t;
    set<pair<int, int>>::iterator it;

    SF(t)
        while (t--)
        {

            SF(n) while (n--) {
                SF(x) SF(y)
                    s.insert({ x,y });
            }

            for (it = s.begin(); it != s.end(); it++) {
                PF(it->first) printf(" "); PF(it->second); printf("\n");
            }
            s.clear();
        }
    return 0;
}

我的输出

-1 -2
-1 2
3 3
3 4
5 -3

如果键相同,我希望键值按降序排序。

【问题讨论】:

  • 什么是SFPF?您是否希望 set 本身对值进行降序排序?

标签: c++ sorting stdset custom-compare


【解决方案1】:

std::set 默认使用std::less 作为默认比较器来比较插入到它的元素。

在您的情况下,您将 std::pair&lt;int,int&gt; 作为您的元素类型,因此,std::set 使用标准中定义的 std::pairdefault operator&lt;,因此您没有得到您想要的结果。

为了实现你的自定义样式比较,你需要提供一个自定义的比较器

template<
    class Key,
    class Compare = std::less<Key>,
 //                 ^^^^^^^^^^^^^^^ --> instead of this
    class Allocator = std::allocator<Key>
> class set;

应该满足compare的要求。 从 C++11 开始,您还可以为此使用 lambda 函数:

以下是示例代码:(See Online)

#include <iostream>
#include <set>
using  pairs = std::pair<int, int>;

int main()
{
    // custom compare
    const auto compare = [](const pairs &lhs, const pairs &rhs) 
    {
        return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second > rhs.second);
    };

    std::set<pairs, decltype(compare)> mySet(compare);

    mySet.emplace(3, 4);
    mySet.emplace(-1, 2);
    mySet.emplace(5, -3);
    mySet.emplace(3, 3);
    mySet.emplace(-1, -2);

    for (const auto& it : mySet)
        std::cout << it.first << " " << it.second << std::endl;
}

输出

-1 2
-1 -2
3 4
3 3
5 -3

【讨论】:

    【解决方案2】:

    Set 默认不会按照你想要的方式排序,所以你必须提供你自己的比较函数。

    struct MyComp
    {
        bool operator()(const pair<int,int>& x, const pair<int,int>& y) const
        {
            return x.first < y.first || (x.first == y.first && x.second > y.second);
        }
    };
    
    set<pair<int,int>, MyComp> s;
    

    【讨论】:

      【解决方案3】:

      正如Jejo 和其他人已经回答的那样,您可以创建一个自定义比较器来指定您希望您的积分如何排序:

      // custom compare
      const auto compare = [](const pairs &lhs, const pairs &rhs) 
      {
          return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second > rhs.second);
      };
      
      set<pair<int, int>, decltype(compare)> mySet(compare);
      

      但是,如果您关心性能,您可能会发现使用 std::vector 并调用 std::sort 比使用 std::set/insert 替代方法快得多:

      #include <vector>
      #include <algorithm>
      using namespace std;
      
      int main() 
      {
          int n, i, hold = 0;
          vector<pair<int, int>> v;
          int x, y, t;
      
          SF(t)
              while (t--)
              {
      
                  SF(n) 
                  v.reserve(n);
                  while (n--) {
                      SF(x) SF(y)
                          v.emplace_back( x,y );
                  }
      
                  // custom comparitor
                  const auto comp = [](const pairs &lhs, const pairs &rhs) 
                  {
                      return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second > rhs.second);
                  };
      
                  sort(v.begin(), v.end(), comp);
      
                  for (const auto &p : v) {
                      PF(p.first) printf(" "); PF(p.second); printf("\n");
                  }
                  v.clear();
              }
          return 0;
      }
      

      插入集合比插入向量然后排序慢的几个原因:

      1. std::set 实现涉及二叉树,通常是红黑树。 See here for details.
      2. 迭代 std::set 中的元素范围是 much slower

      请注意,这两种方法都需要 n 次分配,并且需要 nlog(n) 次操作来进行插入 + 排序。

      【讨论】:

        猜你喜欢
        • 2010-09-21
        • 2011-05-21
        • 1970-01-01
        • 1970-01-01
        • 2013-04-30
        • 1970-01-01
        • 1970-01-01
        • 2021-09-25
        • 2020-05-24
        相关资源
        最近更新 更多