一对整数的哈希算法

3
问题:在保留操作的O(1)算法复杂度的同时,将图的动态邻接列表存储在文件中。
我正在尝试在文件中存储动态双向图。可以添加和删除节点和边缘,并且这些操作必须是O(1)的。我的当前设计如下:
文件1 - 节点
每个节点存储两个整数(插入是追加,删除使用空闲列表):
- 入边数 - 出边数
文件2 - 边缘
每个边缘存储4个整数(插入是追加,删除使用空闲列表+与节点的最后一个边缘交换以更新其新索引):
- 起始节点(指向文件1) - 起始索引(即第三个入边) - 终止节点(指向文件1) - 终止索引(即第二个出边)
文件3 - 链接
作为文件2中边缘位置的开放地址哈希表。当你从文件1读取一个节点时,你知道有x个入边和y个出边。通过这个信息,你可以去文件3中获取每个边缘在文件2中的位置。键值对如下:
- 节点在文件1中的索引(例如第一个节点为0,第二个节点为1) - 0 <= 边缘索引 < 入边数/出边数
如果将文件3的键表示为链式哈希表(不适用于文件,但不需要哈希...)的示例:
Keys (indices from `File 1` + 0 <= index < number of edgesfrom `File 1`, not actually stored)
1 | 0 1 2
2 | 0 1
3 |
4 | 0
5 | 0 1 2

我正在使用qHashQPair来进行哈希,但是冲突的数量非常高。特别是与单个int哈希相比,后者使用qHash非常高效。由于存储的值是指向另一个文件的索引,因此探测成本很高,所以我想减少冲突的数量。
在这种情况下,是否有专门的哈希算法或方法可用于pair of ints,可以更好地执行?或者当然还有其他方法可以避免这个问题,例如如何实现文件中的链接哈希表(我只能想到使用缓冲区,但我认为这对于像我的稀疏图形来说是过度的)?

1
请参考 https://dev59.com/S3NA5IYBdhLWcg3wn_Q1#892640,其中提供了一种相当不错的方法来哈希任意数量的整数。 - Jim Mischel
@JimMischel 哇,这对于我的情况来说真的是一个很棒的哈希算法!终于有比qHash更好的东西了。:-) 通过微调它,我甚至获得了更好的结果(我使用了3个质数而不是2个)。 - Resurrection
1个回答

0
如果您阅读this answer上的评论,它们声称intqHash只是返回未更改的int(这是在内存哈希表中哈希整数的一种相当常见的方式)。因此,使用强大的通用哈希函数将显著减少冲突,尽管您可能会失去一些附带缓存的好处,即附近的键更有可能哈希到磁盘上的同一区域,因此请测量而不是认为较少的冲突意味着更好的性能。我还建议尝试boost::hash_combine从多个哈希值创建总体哈希(仅使用+或XOR是非常糟糕的想法)。然后,如果您正在从磁盘读取,则可能有某种页面大小-例如4k、8k-您必须读取以访问该页面上任何数据的任何位置,因此,如果发生冲突,最好在已加载的页面上查找其他地方,而不是等待从磁盘加载另一页。简单的线性探测大部分时间都可以解决这个问题,但是您可以通过回到页面的开头来进一步改进,以确保在探测其他地方之前搜索了所有内容。

我已经测试了各种整数对的哈希算法,包括现在的hash_combine,但是QPair<int,int>的qHash似乎仍然比其他所有算法表现更好。使用2.1因子似乎根本不会产生冲突,这非常理想(其他算法需要更高的因子)。随着因子降低,冲突迅速增加。这也适用于我尝试过的大约半打算法。关于页面大小的观点是正确的,肯定有助于缓解对磁盘读取过多的担忧。 - Resurrection

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接