在我的情况下,我如何重载相等的方法以使不同的对象在unordered_multimap具有相同的哈希码值

How can I overload equal method to make different objects have same hashcode value in unordered_multimap in my case

本文关键字:unordered 对象 情况下 multimap 哈希码 何重载 重载 方法 我的      更新时间:2023-10-16

我写了这样一张地图:

unordered_multimap<Point, int, StrHash, StrCompare> map

StrHash()是创建哈希码,StrCompare()是解决哈希码冲突。但我想做如下事情:

A 和 B

具有不同的哈希码值,但 A 等于 B,然后运行 StrCompare() 方法。 我该怎么做,就像点A(220,119)Point B(220,220)有不同的哈希码一样。我可以重载哈希码相等的方法吗做A == B?就我而言,我想获得Points,它们相互比较(abs(a.x - b.x) + abs(a.y - b.y) < 3)。就像,Point(220,220)(220,119)(220,118)(220,220) 我的代码如下:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <math.h>
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_multimap;
using namespace std;
using namespace cv;
class StrHash{
public:
    size_t operator()(const Point a) const {
        return a.x * 1000 + a.y;
    }
};
class StrCompare{
public:
    bool operator()(const Point& a, const Point& b) const {
        if (abs(a.x - b.x) + abs(a.y - b.y) < 3) {
            return true;
        }
        else
            return false;
    }
};
int main()
{
    unordered_multimap<Point, int, StrHash, StrCompare> map;
    map.insert(make_pair(Point(30, 120), 1));
    map.insert(make_pair(Point(220, 120), 2));
    map.insert(make_pair(Point(220, 120), 3));
    map.insert(make_pair(Point(220, 120), 4));
    map.insert(make_pair(Point(220, 119), 5));
    map.insert(make_pair(Point(30, 120), 6));
    unordered_multimap<Point, int, StrCompare>::iterator iter1;
    unordered_multimap<Point, int, StrCompare>::iterator iter2;
    for (iter1 = map.begin(); iter1 != map.end();)//
    {
        int num = map.count((*iter1).first);
        iter2 = map.find((*iter1).first);
        if (num > 2) {
            for (int i = 1; i <= num; i++)
            {
                cout << (*iter2).first << "  " << i << endl;
                iter2++;
            }
            iter1++;
        }
        else {
            iter1++;
        }
    }
}

这不是哈希映射/unordered_map的工作方式。根据定义,如果哈希不相等,则对象不相等。不仅如此,你的"相等"运算符还允许像 A(220,119)B(220,220)C(220, 222) 其中 A == B 和 B == C 但 A != C。我看不出有什么方法可以完成你在这个问题中提出的问题,但也许你正在努力解决一个真正的问题?

根据您的评论,听起来您想要std::vector而不是std::unordered_map.然后,您只需使用 std::find 来查找您关心的元素,而不是通过具有无操作哈希的间接过程。

必须这么说,因为如果您的容错能力允许,它会容易得多:您可以将值四舍五入到最接近的 2 或 3 的倍数。


MarkB 关于使用vector的建议非常好......只是出于知识兴趣而列出其他一些。


可以使用 unordered_map 获得所需的功能,但不是很干净:您需要使用映射的代码来编排近似相等的逻辑。 首先,相等函数必须检查实际相等:

struct PointCompare{
    bool operator()(const Point& a, const Point& b) const {
        return a.x == b.x && a.y == b.y;
    }
};

然后,您将需要这样的支持功能:

template <class Map>
auto approx_find(Map& map, const Point& point) -> decltype(map.begin())
{
    decltype(map.end()) it;
    for (int x_offset = -2; x_offset <= 2, ++x_offset)
        for (int y_offset = -2; y_offset <= 2, ++y_offset)
            if (abs(x_offset) + abs(y_offset) < 3 &&
                (it = map.find({point.x + x_offset, point.y + y_offset})) != map.end())
            return it;
    return map.end();
}

然后,您可以使用返回的迭代器来查看您正在考虑插入的Point是否是重复的,以及查找、erase等。

请注意,性能不会很好。 每个approx_find都在有效地围绕Point参数进行搜索,如下所示:

       <------------- X axis -------------->
  ^
  |                   0,-2
  |             -1,-1 0,-1 1,-1
Y axis      -2,0 -1,0 0,0  1,0, 2,0
  |              -1,1 0,1  1,1
  |                   0,2
  v

总而言之,这是 13 次查找 - 或多或少随机分散在哈希表的存储桶周围,因此不是特别适合缓存 - 而不是通常的 1 次。


一个完全不同的选择是使用unordered_multimap来跟踪图形一般区域中的Point - 足够接近,以至于它们可能满足<3接近测试。 例如:

std::unordered_multimap<Point, Point> areas;
Point p = { ...whatever... }; 
// keys for nearby points:
Point around[] = { { (p.x - 2) / 3 * 3, (p.y - 2) / 3 * 3 }, 
                   { (p.x + 2) / 3 * 3, (p.y - 2) / 3 * 3 },
                   { (p.x - 2) / 3 * 3, (p.y + 2) / 3 * 3 },
                   { (p.x + 2) / 3 * 3, (p.y + 2) / 3 * 3 } };

对于四个around[]条目中的每一个,在multimap中执行一个find,以查看是否存在完全匹配或近似匹配:这会将 13 个表探针减少到只有 4 个。 每个multimap键永远不会映射到超过 2 个条目,因为唯一的非近似冲突是在一个区域的相对角落的两个Points