Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何在哈希表和Trie(前缀树)之间进行选择?_Algorithm_Data Structures_Hashtable_Trie - Fatal编程技术网

Algorithm 如何在哈希表和Trie(前缀树)之间进行选择?

Algorithm 如何在哈希表和Trie(前缀树)之间进行选择?,algorithm,data-structures,hashtable,trie,Algorithm,Data Structures,Hashtable,Trie,因此,如果我必须在哈希表或前缀树之间进行选择,有哪些区别因素会导致我选择其中一个而不是另一个。从我自己天真的观点来看,使用trie似乎有一些额外的开销,因为它不是以数组的形式存储的,但就运行时间而言(假设最长的键是最长的英语单词),它基本上可以是O(1)(相对于上限)。也许最长的英语单词是50个字符 一旦得到索引,哈希表就可以立即查找。对键进行散列以获得索引,但似乎需要将近50个步骤 有人能给我提供一个更有经验的观点吗?谢谢 这完全取决于你想解决什么问题。如果您需要做的只是插入和查找,请使用哈希

因此,如果我必须在哈希表或前缀树之间进行选择,有哪些区别因素会导致我选择其中一个而不是另一个。从我自己天真的观点来看,使用trie似乎有一些额外的开销,因为它不是以数组的形式存储的,但就运行时间而言(假设最长的键是最长的英语单词),它基本上可以是O(1)(相对于上限)。也许最长的英语单词是50个字符

一旦得到索引,哈希表就可以立即查找。对键进行散列以获得索引,但似乎需要将近50个步骤


有人能给我提供一个更有经验的观点吗?谢谢

这完全取决于你想解决什么问题。如果您需要做的只是插入和查找,请使用哈希表。如果您需要解决更复杂的问题,例如前缀相关的查询,那么trie可能是更好的解决方案。

一些(通常是嵌入式实时)应用程序要求处理时间独立于数据。在这种情况下,哈希表可以保证已知的执行时间,而trie根据数据而变化。

尝试的优点:

基本要素:

  • 可预测的O(k)查找时间,其中k是键的大小
  • 如果不存在查找,则查找可能需要不到k个时间
  • 支持有序遍历
  • 不需要哈希函数
  • 删除很简单
新业务:

  • 您可以快速查找键的前缀,枚举具有给定前缀的所有条目,等等
链接结构的优点:

  • 如果有许多通用前缀,则共享它们所需的空间
  • 不可变尝试可以共享结构。您可以构建一个只沿一个分支不同的新trie,而不是就地更新trie,其他地方指向旧trie。这对于并发、表的多个同时版本等非常有用
  • 不变的trie是可压缩的。也就是说,它还可以通过hash考虑在后缀上共享结构
哈希表的优点:

  • 每个人都知道哈希表,对吗?您的系统已经有了一个很好的优化实现,比大多数情况下的尝试都要快
  • 你的钥匙不需要有任何特殊的结构
  • 比明显的链接trie结构更节省空间(请参见下面的评论)
使用树:

  • 如果您需要自动完成功能
  • 查找所有以“a”或“axe”开头的单词,依此类推
  • 后缀树是树的一种特殊形式。后缀树有一系列散列无法覆盖的优点

  • 每个人都知道哈希表及其用途,但它并不是一个固定的查找时间,它取决于哈希表有多大,以及哈希函数的计算复杂度

    在大多数工业场景中,即使是很小的延迟/可伸缩性也很重要(例如:高频交易),创建用于高效查找的大型哈希表并不是一个优雅的解决方案。为了减少缓存丢失,还必须考虑数据结构在内存中所占空间的优化


    trie更好地满足需求的一个很好的例子是消息传递中间件。您有一百万个不同类别的消息订阅者和发布者(用JMS术语-主题或交换),在这种情况下,如果您想根据主题(实际上是字符串)过滤消息,您肯定不想为一百万个主题的订阅创建哈希表。更好的方法是将主题存储在trie中,因此当根据主题匹配进行过滤时,其复杂性与主题/订阅/发布者的数量无关(仅取决于字符串的长度)。我喜欢它,因为您可以创造性地使用此数据结构来优化空间需求,从而降低缓存未命中率

    有一件事我没有看到有人明确提到,我认为要记住这件事很重要。哈希表和各种类型的try通常都有
    O(k)
    操作,其中
    k
    是字符串的长度,单位为位(或等效为字符)


    这是假设你有一个好的散列函数。如果您不希望“farm”和“farm animals”散列为相同的值,那么散列函数将必须使用密钥的所有位,因此散列“farm animals”的时间应该是“farm”的两倍(除非您处于某种滚动散列场景中,但也有一些类似的操作节省场景)。用香草果酱,很清楚为什么插入“农场动物”的时间是“农场”的两倍。从长远来看,压缩尝试也是如此。

    哈希表实现与基本的Trie实现相比,空间效率更高。但是对于字符串,排序在大多数实际应用中是必要的。但是哈希表完全扰乱了字母顺序。现在,如果您的应用程序正在执行基于词法顺序的操作(如部分搜索、具有给定前缀的所有字符串、按排序顺序排列的所有单词),则应该使用Tries。仅对于查找,应使用哈希表(可以说,它提供了最短的查找时间)


    p.S.:除此之外,三元搜索树(TST)将是一个很好的选择。它的查找时间比哈希表长,但在所有其他操作中都是高效的。而且,它比tries更节省空间。

    在trie上的插入和查找与输入字符串O(s)的长度成线性关系

    散列将为查找ans插入提供一个O(1),但首先必须根据输入字符串计算散列,该字符串也是O(s)

    结论:在这两种情况下,渐近时间复杂度都是线性的

    trie的开销比