我一直在研究尝试并检查它们的优点和缺点。它们在许多实际应用中非常有用,例如字典,拼写检查器等,因为它们具有恒定的O(m)查找(其中m是字符串的长度)以及其他优点,例如提供有序的字符串检索和获得公共前缀。所以,我的优势非常明显,但局限性有点令人困惑。
我正在关注此链接:https://en.wikipedia.org/wiki/Trie
此处列出的缺点是:
跟进问题 - 为什么会出现涉及二级存储的情况?是不是也应该将尝试存储在主存储器中。如果它们存储在二级存储中,那么无论如何都不会使用trie,因为磁盘访问总是会导致更多次。
后续问题:是否是因为尝试将包含更多的引用/指针以将每个字符连接到下一个字符,并且消耗的字节数多于存储为一整串? (我从这里的答案之一得到了这个理由)。任何人都可以详细说明这个吗?
我真的很感激这里的一些帮助。感谢。
答案 0 :(得分:3)
首先,"常数O(m)查找"毫无意义。 trie中的查找时间是O(m):它取决于你查找的字符串的长度。
构造良好的哈希表(即良好的哈希函数和合理的加载因子)具有O(1)查找时间。
假设有能力的构造,在哈希表中查找字符串将比在特里查找字符串快得多。
Tries和哈希表用于不同的事情。如果你想要的只是查找单词的能力,那么哈希表会更快。如果你想找到共同的前缀,有序的检索,或做类似的事情,那么你想要一个特里。
哈希表可以非常快速地查找单个字符串。它就像一匹纯种赛马。它可以做所有。另一方面,特里是一个可以做很多事情的主力。它的查找速度永远不会像哈希表一样快,但它可以做很多哈希表无法做到的事情。
例如,查找所有以" pre"开头的单词因为你必须搜索所有的单词,所以花费O(n)时间用字典。使用trie,需要三个探测器才能找到包含所有这些单词的子树,然后你要做的就是遍历那个子树。当然,最坏的情况是O(n),但只有当你的特里的所有单词都以" pre"开头时才会出现。
虽然进入磁盘的速度比整个磁带都在内存中要慢,但是说基于磁盘的trie没有替代方案的优势是错误的。如果数据不适合内存,那么无论您使用何种数据结构,您都需要一些外部(即非内存)存储。当磁盘上的数据访问速度较慢时,这一事实并没有从根本上改变trie与hash表的优缺点。例如,在查找具有特定前缀的所有单词时,基于磁盘的trie仍然比基于磁盘的哈希表更快。
哈希表的开销通常是它包含的单词数的常数倍。也就是说,除了存储字符串所需的内存之外,还存在每字符串开销来存储哈希代码和字符串之间的映射。
特里的记忆更多一些。在最坏的情况下,每个字符有一个节点。所有这些小节点分配开始累加。想象一下包含200,000个单词的字典,平均字长为5个字符。这是一百万个开销节点。
幸运的是,有很多方法可以大大压缩trie,而不会损失很多(如果有的话)性能。由此产生的数据结构比天真构造的数据结构小得多且缓存更友好。
答案 1 :(得分:0)
这已经有一段时间了,但是我想补充说,如果有人想知道,一个好的散列函数应该花费O(1)时间来获取固定内存值,例如原始类型或固定长度列表原始类型。通常对要散列的所有值应用相同的逻辑运算(逻辑左移和右移,按位运算等)。无论使用何种值,这些操作都需要相同的时间。这使得散列表在存储耗尽可预测空间量的值时更快且相对可靠。如果遍历基础字符数组并且仅间隔选择字符以确保始终散列相同数量的内存,则也可以在O(1)时间内散列字符串。
例如,对于长度为10的字符串,您可以在基础字符数组中散列10个字符,而对于长度为100的字符串,则根据每个第十个字符进行散列。
因此,为了回答你的问题,散列通常在恒定时间内完成,而从trie插入或检索是O(n)时间,其中n是要插入或检索的值的长度。即使在实践中几乎没有差别,常数也具有可预测的优点。哈希表上的所有操作每次都会花费相同的时间,给予或接受。但是使用trie(代表威尔士地名字典),搜索Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch并在最后改变一个角色将比搜索“a”花费更多的时间。在意识到它不在字典中之前,系统会吃掉整个字符串。谷歌和其他科技公司倾向于选择漂亮,可预测(但均匀分布)的散列来避免安全问题。