C 用AVL树进行散列

C 用AVL树进行散列,c,algorithm,data-structures,hash,C,Algorithm,Data Structures,Hash,我正在用C语言编写一个搜索程序。我使用了散列数据结构。我只存储了一个单词,然后从该单词中指向该单词所在的字符串。因此,每当用户给出一个单词时,包含该单词的所有字符串都将被给出 但是我没有使用链表,而是在哈希中使用了AVL树。简而言之,键中的下一个节点指向AVL树的根。这可以将时间复杂度从O(n)降低到O(logn) 假设一个节点有数千个字符串连接在一起。将哈希与AVL树一起使用好吗。(我还为此尝试了数据结构。) 有没有更好的算法 假设一个节点有数千个字符串连接在一起。将哈希与AVL树一起使用好吗

我正在用C语言编写一个搜索程序。我使用了散列数据结构。我只存储了一个单词,然后从该单词中指向该单词所在的字符串。因此,每当用户给出一个单词时,包含该单词的所有字符串都将被给出

但是我没有使用链表,而是在哈希中使用了AVL树。简而言之,键中的下一个节点指向AVL树的根。这可以将时间复杂度从O(n)降低到O(logn)

假设一个节点有数千个字符串连接在一起。将哈希与AVL树一起使用好吗。(我还为此尝试了数据结构。)

有没有更好的算法

假设一个节点有数千个字符串连接在一起。将哈希与AVL树一起使用好吗

不。在这一点上,你甚至不再使用哈希表了——如果你对O(logn)的性能感到满意,那么直接使用树,不要在顶部使用哈希表


如果在一个散列桶下有“数千个字符串”,那么您的散列表就太小了——理想情况下,大多数桶中最多应该有一个对象。使用较大的哈希表可以获得哈希表可以提供的O(1)插入/查找性能。

闭合寻址哈希-这就是您正在使用的-通过选取一些哈希函数来工作,使用它在各个存储桶之间分布元素,然后每个存储桶都有一些数据结构来处理冲突。您的建议(每个bucket使用AVL树)确实会使查找的最坏情况性能逐渐提高,但要使其值得,您需要进行大量的冲突。有一个有趣的结果表明,如果您有一个足够好的散列函数,并将n个对象放入一个n槽散列表中,那么最大的bucket的预期大小为O(logn/logn),这是一个非常小的数字

如果您通过切换到树来解决冲突而获得了性能优势,那么这可能意味着您在每个bucket中有太多的元素。例如,这可能意味着您没有足够的存储桶来容纳您拥有的元素数量。在这种情况下,增加存储桶的数量可能是比更有效地解决冲突更好的解决方案


这也可能意味着你没有一个很好的散列函数,这会导致你的字符串聚集在一小部分桶中。在这种情况下,选择更好的哈希函数可能会比使用AVL树带来更好的性能收益。

哈希算法有问题,或者您的存储桶太少。一个桶不应该包含超过一把钥匙

不要试图支撑大水桶;首先修复导致铲斗变大的实际问题

作为参考,我将系统的
/usr/share/dict/words
中的99171个单词加载到Perl哈希表[1]中。得到的哈希表有131072个bucket,没有一个bucket超过7个键,并且它最多需要三次比较来定位99%输入的元素(或确定缺少元素)

按键:99171
电话:131072
分布:
带0键的存储桶:61461
带1把钥匙的桶:46668
带2把钥匙的桶:17547
带3把钥匙的桶:4343
带4把钥匙的桶:903
带5把钥匙的桶:133
带6把钥匙的桶:16
带7把钥匙的桶:1
搜索缺少的密钥:
0比较:47%的时间≤0比较:47%的时间
1比较:36%的时间≤1比较:83%的时间
2次比较:13%的时间≤2次比较:96%的时间
3次比较:3%的时间≤3次比较:99%的时间
4次比较:1%的时间≤4次比较:100%的时间
5次比较:0%的时间≤5次比较:100%的时间
6次比较:0%的时间≤6比较:100%的时间
7比较:0%的时间≤7个比较:100%的时间
搜索当前密钥:
1比较:70%的钥匙≤1比较:70%的钥匙
2比较:23%的键≤2个比较:93%的键
3个比较:5%的键≤3个比较:99%的键
4比较:钥匙的1%≤4个比较:100%的键
5比较:0%的键≤5个比较:100%的键
6比较:0%的键≤6比较:100%的钥匙
7比较:0%的键≤7个比较:100%的键
通过用AVL树替换链表,您只是在等待空间


现在,哈希确实提供了O(1)查找和摊销O(1)插入,但它们不是特别紧凑。如果您可以使用稍微慢一点的查找(O(logn))查找,那么可以通过使用某种树而不是散列来节省大量空间

有很多选择。一种是a,它被认为在使用公共前缀存储大量值时特别有效


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

  • 如果您的存储桶包含太多冲突,需要BST来管理,您应该重新考虑哈希函数或存储桶的数量。@StoryTeller是的,它包含太多冲突,这就是为什么我想用AVL实现哈希。对于英语单词,我会使用32位FNV哈希和16k左右的表大小,碰撞应该是罕见的。当你扩展输入文本时,你可能还需要增加able,但可能不能超过128k左右,这是任何PC都应该轻松处理的。我同意StoryTeller的观点。哈希算法有问题,或者您的存储桶太少。一个桶不应该包含超过一把钥匙。不要试图支撑大水桶;首先修复导致铲斗变大的实际问题。作为参考,我将
    /usr/share/dict/words
    中的99171个单词加载到Perl