我正在研究C中的搜索程序。我使用散列数据结构。我只是存储了一个单词,从那个单词中我指出了该单词存在的字符串。因此,每当用户给出一个单词时,将给出包含该单词的所有字符串。
但是我没有使用链表,而是使用了散列中的AVL树。简而言之,密钥中的下一个节点指向AVL树的根。这可以将时间复杂度从O(n)减少到O(log n)。
假设一个节点有数千个字符串连接在一起。使用AVL树散列是否合适。 (我也尝试过尝试数据结构。)
有没有更好的算法呢?
答案 0 :(得分:3)
假设一个节点有数千个字符串连接在一起。使用AVL树进行散列是否合适。
没有。此时,您甚至几乎不再使用哈希表 - 如果您对O(log n)性能感到满意,请直接使用树,而不要使用哈希表。
如果你有数千个字符串"在一个哈希桶下,你的哈希表太小了 - 理想情况下,大多数桶最多应该有一个对象。使用更大的哈希表来获取哈希表可以提供的O(1)插入/查找性能。
答案 1 :(得分:3)
封闭寻址散列 - 这是你正在使用的 - 通过选择一些散列函数,使用它在桶之间分配元素,然后每个桶有一些数据结构来处理冲突。你提出的建议(每桶使用一个AVL树)确实使查找的最坏情况性能渐进地更好,但是为了它值得你需要进行大量的冲突。有一个很好的结果,如果你有一个足够好的哈希函数并将n个对象放入一个n-slot哈希表,那么最大的桶的预期大小为O(log n / log log n),这是一个非常小的数字。
如果您通过切换到树来解决冲突而获得性能提升,则可能意味着您在每个存储桶中都有太多元素。例如,这可能意味着您没有足够的存储桶来存储您拥有的元素数量。在这种情况下,增加桶的数量可能是比更有效地解决冲突更好的解决方案。
这也可能意味着你没有一个非常好的哈希函数,这会导致你的字符串聚集在少量的桶中。在这种情况下,选择更好的哈希函数可能会比使用AVL树获得更好的性能获胜。
答案 2 :(得分:2)
哈希算法存在问题,或者您的存储桶太少。一个桶不应该包含多个密钥。
不要试图支持大水桶;解决导致存储桶变大的实际问题。
作为参考,我将系统的/usr/share/dict/words
中的99,171个单词加载到Perl哈希表 [1] 中。生成的哈希表有131,072个桶,没有桶有超过7个密钥,并且最多需要三次比较才能找到99%的输入元素(或确定它缺失)。
Keys: 99,171
Buckets: 131,072
Distribution:
Buckets with 0 keys: 61,461
Buckets with 1 keys: 46,668
Buckets with 2 keys: 17,547
Buckets with 3 keys: 4,343
Buckets with 4 keys: 903
Buckets with 5 keys: 133
Buckets with 6 keys: 16
Buckets with 7 keys: 1
Search for absent keys:
0 comparisons: 47% of the time ≤0 comparisons: 47% of the time
1 comparison: 36% of the time ≤1 comparison: 83% of the time
2 comparisons: 13% of the time ≤2 comparisons: 96% of the time
3 comparisons: 3% of the time ≤3 comparisons: 99% of the time
4 comparisons: 1% of the time ≤4 comparisons: 100% of the time
5 comparisons: 0% of the time ≤5 comparisons: 100% of the time
6 comparisons: 0% of the time ≤6 comparisons: 100% of the time
7 comparisons: 0% of the time ≤7 comparisons: 100% of the time
Search for present keys:
1 comparison: 70% of keys ≤1 comparison: 70% of the keys
2 comparisons: 23% of keys ≤2 comparisons: 93% of the keys
3 comparisons: 5% of keys ≤3 comparisons: 99% of the keys
4 comparisons: 1% of keys ≤4 comparisons: 100% of the keys
5 comparisons: 0% of keys ≤5 comparisons: 100% of the keys
6 comparisons: 0% of keys ≤6 comparisons: 100% of the keys
7 comparisons: 0% of keys ≤7 comparisons: 100% of the keys
通过用AVL树替换链表,你只是在等空间。
现在,哈希确实提供了O(1)查找和摊销的O(1)插入,但它们并不特别紧凑。如果您使用略慢的查找(O(log n))查找,则可以通过使用某种树而不是来节省大量空间。
有很多选择。一个是ternary search tree,据说在使用公共前缀存储大量值时效率特别高。
perl -MDevel::Peek -nle'++$h{$_} END{ Dump(%h,0) }' /usr/share/dict/words