Hash树(散列树)和Trie树(字典树、前缀树)

1.Hash树

理想的情况是希望不经过任何比较,一次存取便能得到所查的记录,
那就必须在记的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和一个唯一的存储位置相对应。因而在查找时,只要根据这个对应关系f找到
给定值K的像f(K)。由此,不需要进行比较便可直接取得所查记录。在此,我们称这个对应关系为哈希(Hash)函数,按这个思想建立的表为哈希表

在哈希表中对于不同的关键字可能得到同一哈希地址,这种现象称做冲突。在一般情况下,冲突只能尽可能地减少,而不能完全避免。因为哈希函数是从关键字集合
到地址集合的映像。通常关键字的集合比较大,它的元素包括所有可能的关键字,而地址集合的元素仅为哈希表中的地址值。在一般情况下,哈希函数是一个压缩映像函数,这就不可避免的要产生冲突。

哈希树的理论基础

质数分辨定理
简单地说就是:n个不同的质数可以“分辨”的连续整数的个数和他们的乘积相等。“分辨”就是指这些连续的整数不可能有完全相同的余数序列。

例如:
从2起的连续质数,连续10个质数就可以分辨大约M(10) =2*3*5*7*11*13*17*19*23*29= 6464693230
个数,已经超过计算机中常用整数(32bit)的表达范围。连续100个质数就可以分辨大约M(100) = 4.711930 乘以10的219次方。

插入

我们选择质数分辨算法来建立一棵哈希树。
选择从2开始的连续质数来建立一个十层的哈希树。第一层结点为根结点,根结点下有2个结点;第二层的每个结点下有3个结点;依此类推,即每层结点的子节点数目为连续的质数。到第十层,每个结点下有29个结点。
同一结点中的子结点,从左到右代表不同的余数结果。
例如:第二层结点下有三个子节点。那么从左到右分别代表:除3余0,除3余1,除3余2.
对质数进行取余操作得到的余数决定了处理的路径。

下面我们以随机的10个数的插入为例,来图解HashTree的插入过程

2.Trie树

字典树(Trie)可以保存一些字符串->值的对应关系。基本上,它跟 Java 的 HashMap 功能相同,都是 key-value 映射,只不过 Trie 的 key 只能是字符串。
  Trie 的强大之处就在于它的时间复杂度。它的插入和查询时间复杂度都为 O(k) ,其中 k 为 key 的长度,与 Trie
中保存了多少个元素无关。Hash 表号称是 O(1) 的,但在计算 hash 的时候就肯定会是 O(k) ,而且还有碰撞之类的问题;Trie
的缺点是空间消耗很高。
      Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
      Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

以英文单词构建的字典树为例,这棵Trie树中每个结点包括26个孩子结点,因为总共有26个英文字母(假设单词都是小写字母组成)。

下面我们有and,as,at,cn,com这些关键词,那么如何构建trie树呢?

从上面的图中,我们或多或少的可以发现一些好玩的特性。

第一:根节点不包含字符,除根节点外的每一个子节点都包含一个字符。

第二:从根节点到某一节点,路径上经过的字符连接起来,就是该节点对应的字符串。

第三:每个单词的公共前缀作为一个字符节点保存。

参考文章:

Trie树:应用于统计和排序     http://blog.csdn.net/hguisu/article/details/8131559

图文详解HashTree(哈希树)   http://blog.csdn.net/yang_yulei/article/details/46337405

时间: 2024-10-08 08:16:10

Hash树(散列树)和Trie树(字典树、前缀树)的相关文章

208. Implement Trie (Prefix Tree) 实现前缀树

Implement a trie with insert, search, and startsWith methods. Note: You may assume that all inputs are consist of lowercase letters a-z. var Trie = function() { this.nodes = {}; }; Trie.prototype.insert = function(word) { let node = this.nodes, cur;

Trie(前缀树)

1 什么是Trie Trie也叫前缀树,因为存放和查找的时候都是将关键字字符串从前到后一个字母一个字母的进行的,所以叫前缀树.根节点不存放字母,其它的每个结点都存放一个字母.如果某个结点的字母是要给关键字的最后一个字母,那么该节点还存放该路径对应的关键字的值.也就是说,整个关键字字符串存放在一条路径上.另外前缀树是有序树,每个结点的左子树存放的字母比该结点的要小,右子树存放的字母比该结点要大. 2 怎样创建一棵前缀树 可以用三个数组实现一棵前缀树,一个数组是树本身,一个是key,一个是value

力扣208——实现 Trie (前缀树)

这道题主要是构造前缀树节点的数据结构,帮助解答问题. 原题 实现一个 Trie (前缀树),包含?insert,?search, 和?startsWith?这三个操作. 示例: Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 true trie.search("app"); // 返回 false trie.startsWith("app

C++学习笔记 <hash_map> <散列映射>

对于大型容器而言hash_map要比map快5至10倍的元素查找速度. map对其元素类型要求有一个<,hash_map要求一个==和一个散列函数. map<string,int>  m1;   //用<比较串 map<string,int Nocase>   m2;       //用Nocase()比较串 hash_map<string,int>   hm1;        //用Hash<string>()散列,用==比较 hash_map

散列树(Hash Tree)

用质数分辨算法来建立一棵散列树(Hash树). 选择从2开始的连续质数来建立一个十层的哈希树.第一层结点为根结点,根结点下有2个结点:第二层的每个结点下有3个结点:第三层的每个结点下有5个结点:依此类推,即每层结点的子节点数目为连续的质数.到第十层,每个结点下有29个结点. 同一结点中的子结点,从左到右代表不同的余数结果.例如:第二层结点下有三个子节点.那么从左到右分别代表:除3余0,除3余1,除3余2.      对质数进行取余操作得到的余数决定了处理的路径.结点:结点的关键字(在整个树中是唯

UVa 11732 &quot;strcmp()&quot; Anyone? (左儿子右兄弟前缀树Trie)

题意:给定strcmp函数,输入n个字符串,让你用给定的strcmp函数判断字符比较了多少次. 析:题意不理解的可以阅读原题https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2832 字符串很多,又很长,如果按照题目的意思两两比较,肯定会TLE,所以要用前缀树(Trie)来解决,当然只是用简单的前缀树也会TLE的, 我们必须对其进行优化,看了

常用算法之Trie【字典树,前缀树】

Trie中文名又叫做字典树,前缀树等,因为其结构独有的特点,经常被用来统计,排序,和保存大量的字符串,经常见于搜索提示,输入法文字关联等,当输入一个值,可以自动搜索出可能的选择.当没有完全匹配的结果时,可以返回前缀最为相似的可能. 其实腾讯的面试题有一个:如何匹配出拼写单词的正确拼写.其实用匹配树非常合适. 基本性质: 1.根节点不含有字符,其余各节点有且只有一个字符. 2.根节点到某一节点中经过的节点存储的值连接起来就是对应的字符串. 3.每一个节点所有的子节点的值都不应该相同. 借用一下维基

·专题」 Trie(前缀树)

重新整理Trie的内容,还有一种叫做双链键树,不过到现在也不会写. Trie 可以称为字典树,也叫做前缀树,叫字典树很形象,叫前缀树可以很好的区分,因为还有一种树叫做后缀树 自己就不瞎总结了,写估计也写不好.关键是时间不允许. 参考两个blog A   B 先给一个比较标准的模板 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 7 #defin

【暑假】[实用数据结构]前缀树 Trie

前缀树Trie Trie可理解为一个能够快速插入与查询的集合,无论是插入还是查询所需时间都为O(m) 模板如下: 1 const int maxnode = 1000+10; 2 const int sigma_size = 26; 3 4 struct Trie{ 5 int ch[maxnode][sigma_size]; 6 int val[maxnode]; 7 int sz; 8 9 void clear(){ sz=1; memset(ch[0],0,sizeof(ch[0]));