哈希与AVL树

时间:2017-10-02 19:46:15

标签: c algorithm data-structures hash

我正在研究C中的搜索程序。我使用散列数据结构。我只是存储了一个单词,从那个单词中我指出了该单词存在的字符串。因此,每当用户给出一个单词时,将给出包含该单词的所有字符串。

但是我没有使用链表,而是使用了散列中的AVL树。简而言之,密钥中的下一个节点指向AVL树的根。这可以将时间复杂度从O(n)减少到O(log n)。

假设一个节点有数千个字符串连接在一起。使用AVL树散列是否合适。 (我也尝试过尝试数据结构。)

有没有更好的算法呢?

3 个答案:

答案 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,据说在使用公共前缀存储大量值时效率特别高。

  1. 我使用了perl -MDevel::Peek -nle'++$h{$_} END{ Dump(%h,0) }' /usr/share/dict/words