问题提出:
set和map都是有序容器。
以下问题以set为例,map同理。

以下情况如何建立set?

  • 1 自定义的结构体(或者类)(没有自带的比较方法)
  • 2 按字符串长度为比较方法,建立一个set<string>

1、结构体中自定义比较方法。

记得STL一般是按<排序的自定义<就可以

struct Point {
    int x;
    int y;
    Point(int xx, int yy):x(xx),y(yy){}
    bool operator < (const Point& b) {
        if (x == b.x) return y > b.y;
        return x > b.x;
    }
}

但是:编译错误:
错误 C2678 二进制“<”: 没有找到接受“const _Ty”类型的左操作数的运算符(或没有可接受的转换)

对比别人的做法后,原来应该这样写:


struct Point {
    int x;
    int y;
    Point(int xx, int yy):x(xx),y(yy){}
    friend bool operator < (const Point& a, const Point& b);
};
bool operator < (const Point& a, const Point& b) {
    if (a.x == b.x) return a.y > b.y;
    return a.x > b.x;
}

不太好理解哦。。只能说是STL的设计就是这样的呗。。

不过需要注意一点: set在插入操作中需要比较a<b? b <a? 两步。我猜测不能将运算符重载为成员函数和这个有关。

2、直接在建立set时自定义比较方法

直接看代码:

struct cmp {
    bool operator()(const string& a, const string& b)const{
        if (a.length() == b.length()) return a < b;
        return a.length() < b.length();
    }
};
set<string, cmp> collected;

这样,collected中的内容是首先按字符串长度排序,其次按字典序。

注意点: 自定义的比较函数是一个伪函数。原因: set本质是一个模板类,模板类只能用具体的数据类型作参数来实例化。使用真正的函数是不行的。

(这里还遇到了奇奇怪怪的问题: 伪函数bool cmp::operator()(const string& a, const string& b)const;必须声明为常函数…不然会报错。。但是别人的做法并不会这样)

3、自定义比较的关键: 避免歧义。

无论是哪种自定义方式,必须要保证: a < b与b < a不能同时成立。