C++ map使用自定义比较函数

C++的map容器可以建立映射,如果key使用自定义类,需要重载operator<运算符,但是由于find方法使用operator<来完成, 因此常常会遇到意想不到的意外。尽管有人说可以通过std::find_if通过重载operator==运算来保证可靠查找,但是也会遇到意想不到的意外。

以下的代码中,几种方法在find时均会遇到意想不到的意外,无法可靠find相应的key。

//
// Created by Denlee on 21-12-5.
//

#include <map>
#include <iostream>
#include <algorithm>
#include <assert.h>

class Point {
private:
    int _x, _y;

public:
    Point();
    Point(int x, int y);
    Point(const Point &pt);
    ~Point();
    Point &operator=(const Point &pt);
    bool operator==(const Point &pt) const;
    // partial order
    bool operator<(const Point &pt) const;

    friend std::ostream &operator<<(std::ostream &out, const Point &pt);
};

Point::Point() {
    _x=_y=0;
}

Point::Point(int x, int y) {
    _x = x; _y = y;
}

Point::Point(const Point &pt) {
    _x = pt._x;
    _y = pt._y;
}

Point::~Point() {

}

Point& Point::operator=(const Point &pt) {
    if(this != &pt) {
        this->_y = pt._y;
        this->_x = pt._x;
    }
    return *this;
}

bool Point::operator==(const Point &pt) const {
    return this->_x == pt._x && this->_y == pt._y;
}

bool Point::operator<(const Point &pt) const {
    return this->_x < pt._x || this->_y < pt._y;
}

std::ostream &operator<<(std::ostream &out, const Point &pt) {
    out << "(" << pt._x << "," << pt._y << ")";
    return out;
}

int main() {
    int i, j;
    int x = 10;
    int y = 9;

    std::map<Point, int> map_point;
    int order = 0;
    for(i=0; i<x; i++) {
        for(j=0; j<y; j++) {
            map_point.insert(std::pair<Point, int>(Point(i,j), order++));
        }
    }
    assert(map_point.size() == x * y);

    std::cout << "--------------find-----------------\n";
    for(i=0; i<x; i++) {
        for(j=0; j<y; j++) {
            std::map<Point, int>::const_iterator it;
            it = map_point.find(Point(i,j));
            if(it != map_point.end()) {
                std::cout << it->first << ": " << it->second << "\n";
            } else {
                std::cout << "(" << i << "," << j << ")\n";
            }
        }
    }

    std::cout << "-------------count------------------\n";
    for(i=0; i<x; i++) {
        for(j=0; j<y; j++) {
            Point pt(x,y);
            if(map_point.count(pt)) {
                std::cout << pt << ": " << map_point[pt] << "\n";
            } else {
                std::cout << "(" << i << "," << j << ")\n";
            }
        }
    }

    std::cout << "---------------find_if----------------\n";
    for(i=0; i<x; i++) {
        for(j=0; j<y; j++) {
            Point pt(x,y);
            std::map<Point,int>::iterator it = std::find_if(map_point.begin(),map_point.end(),[pt](std::pair<Point,int> obj){return obj.first == pt; });
            if(it  != map_point.end()) {
                std::cout << it->first << ": " << it->second << "\n";
            } else {
                std::cout << "(" << i << "," << j << ")\n";
            }
        }
    }

    std::cout << "-------------enumerate------------------\n";
    for(const auto& v : map_point) {
        std::cout << v.first << ": " << v.second << "\n";
    }

    return 0;
}

对于自定义类作为key,最好使用std::string来表征,并通过自定义比较函数来实现可靠查找.

// Point类增加成员函数
std::string to_string() const;

std::string Point::to_string() const {
    return std::to_string(_x) + std::to_string(_y);
}

// 自定义比较函数
class point_key_comp {
public:
    bool operator()(const Point& pt1, const Point& pt2)const {
        return pt1.to_string() < pt2.to_string();
    }
};

//.....
//使用Point类型作为map的key
std::map<Point, int, point_key_comp> map_point;

参考资料:

[1] C++ STL: map自定义键值类型. C++ STL: map自定义键值类型_爱吃柚子的好奶罐-CSDN博客_c++ map 自定义类.

[2] C++ 自定义比较函数(map和multimap)详解. C++ 自定义比较函数(map和multimap)详解.

[3] C++中set/unordered_set 自定义比较规则. C++中set/unordered_set 自定义比较规则_nepu_bin的博客-CSDN博客.

[4] C++ STL无序容器自定义哈希函数和比较规则(超级详细). C++ STL无序容器自定义哈希函数和比较规则(超级详细).

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值