引html
在各类数据结构(线性表、树等)中,记录在结构中的相对位置是随机的。所以在机构中查找记录的时需要进行一系列和keyword的比較。这一类的查找方法创建在“比較”的基础上。查找的效率依赖于查找过程当中所进行的比較次数。算法
以前咱们介绍的各类基于比較的树查找算法,这些查找算法的效率都将随着数据记录数的增加而降低。数据库
不过有的比較慢(时间复杂度为O(n)),有的比較快(时间复杂度是O(logn))而已。这些查找算法的平均查找长度是在一种比較理想的状况下得到的。数组
在实际应用其中,对数据结构中数据的频繁添加和删除将不断地改变着数据的结构。安全
这些操做将可能致使某些数据结构退化为链表结构,那么其性能一定将降低。数据结构
为了不出现这样的状况而採取的调整措施。又不可避免的添加了程序的复杂程度以及操做的额外时间。
函数
哈希表 性能
理想的状况是 但愿不通过不论什么比較,一次存取便能获得所查的记录。那就必须在记的存储位置和它的keyword之间创建一个肯定的相应关系f,使每个keyword和一个惟一的存储位置相相应。于是在查找时。仅仅要依据这个相应关系f找到给定值K的像f(K)。由此,不需要进行比較即可直接取得所查记录。在此,咱们称这个相应关系为哈希(Hash)函数。按这个思想创建的表为 哈希表。
哈希树(HashTree)算法就是要提供一种在理论上和实际应用中均能有效地处理冲突的方法。通常的哈希(Hash)算法都是O(1)的,而且基本是以空间换时间。这很是easy致使对存储空间无限制的需求。优化
本文中哈希树(HashTree)算法在实际操做中使用了一些技巧使得对空间的需求控制在必定范围内。即空间需求仅和所需要存储的对象个数有关,不会无限制地“膨胀”下去。 spa
哈希树的理论基础
“分辨”就是指这些连续的整数不可能有全然一样的余数序列。
(这个定理的证实详见:http://wenku.baidu.com/view/16b2c7abd1f34693daef3e58.html)
好比:
从2起的连续质数。连续10个质数就可以分辨大约M(10) =2*3*5*7*11*13*17*19*23*29= 6464693230 个数,已经超过计算机中常用整数(32bit)的表达范围。连续100个质数就可以分辨大约M(100) = 4.711930 乘以10的219次方。
而依照眼下的CPU水平,100次取余的整数除法操做差点儿不算什么难事。在实际应用中。整体的操做速度每每取决于节点将keyword装载内存的次数和时间。通常来讲。装载的时间是由keyword的大小和硬件来决定的;在一样类型keyword和一样硬件条件下,实际的整体操做时间就主要取决于装载的次数。
他们之间是一个成正比的关系。
插入
咱们选择质数分辨算法来创建一棵哈希树。
选择从2開始的连续质数来创建一个十层的哈希树。第一层结点为根结点。根结点下有2个结点。第二层的每个结点下有3个结点。依此类推,即每层结点的子节点数目为连续的质数。
到第十层,每个结点下有29个结点。
同一结点中的子结点。从左到右表明不一样的余数结果。
好比:第二层结点下有三个子节点。那么从左到右分别表明:除3余0,除3余1。除3余2.
对质数进行取余操做获得的余数决定了处理的路径。
结点结构:结点的keyword(在整个树中是惟一的),结点的数据对象。结点是否被占领的标志位(标志位为真时,keyword才被以为是有效的),和结点的子结点数组。
哈希树的节点结构
struct Node { keyType key ; ValueType value ; bool occupied ; //用occupied来表示节点是否被占领。假设节点的keyword(key)有效。那么occupied应该设置位true,不然设置为false。(假设在创建当初就创建所有的节点。那么所消耗的计算时间和磁盘空间是巨大的。struct Node* subNodes[1] ; //咱们用subNodes[i]来表示节点的第i个子节点的地址。(此技术在跳跃表中有介绍,可翻看前面博客) } ;
在实际使用其中,仅仅需要初始化根节点就可以開始工做。
子节点的创建是在有不少其它的数据进入到哈希树中的时候创建的。所以可以说哈希树和其它树同样是一个动态结构。)
如下咱们以随机的10个数的插入为例,来图解HashTree的插入过程,这个史上最清晰的图解,你必定能看的明确^_^
有读者可能有疑问,假设一直冲突下去怎么办?首先,若keyword是整型。咱们的10层哈希树全然可以分辨出来它们,这是质数分辨算法决定的。
(咱们事实上也可以把所有的键-值节点放在哈希树的第10层叶节点处,这第10层的满节点数就包括了所有的整数个数。但是假设这样处理的话,所有的非叶子节点做为键-值节点的索引,这样使树结构庞大,浪费空间)
【这里没有说的太清楚,此图是以2開始的连续质数建立的,即:从上到下的层级中的每个节点中的子树个数为二、三、五、七、十一、1三、1七、1九、2三、29。第一层中的每个节点的子树个数为2,第二层中的每个节点子树个数为5.。。。。
上图中的子树上的数字。是其父节点的子树指针数组的索引值】
查找
哈希树的节点查找过程和节点插入过程相似,就是对keyword用质数序列取余,依据余数肯定下一节点的分叉路径,直到找到目标节点。
所以可以依据自身需要在时间和空间上寻求一个平衡点。
删除
哈希树的节点删除过程也很是easy。哈希树在删除的时候,并不作不论什么结构调整。
长处
一、结构简单
从哈希树的结构来讲。很的简单。每层节点的子节点个数为连续的质数。子节点可以随时建立。所以哈希树的结构是动态的,也不像某些哈希算法那样需要长时间的初始化过程。哈希树也没有必要为不存在的keyword提早分配空间。
需要注意的是哈希树是一个单向添加的结构,即随着所需要存储的数据量添加而增大。
即便数据量下降到原来的数量,但是哈希树的总节点数不会下降。
这样作的目的是为了不结构的调整带来的额外消耗。
二、查找迅速
从算法过程咱们可以看出,对于整数,哈希树层级最多能添加到10。
所以最多仅仅需要十次取余和比較操做,就可以知道这个对象是否存在。
这个在算法逻辑上决定了哈希树的优越性。
通常的树状结构。每每随着层次和层次中节点数的添加而致使不少其它的比較操做。操做次数可以说没法准确肯定上限。而哈希树的查找次数和元素个数没有关系。假设元素的连续keyword总个数在计算机的整数(32bit)所能表达的最大范围内,那么比較次数就最多不会超过10次。一般低于这个数值。
三、结构不变
从删除算法中可以看出,哈希树在删除的时候,并不作不论什么结构调整。这个也是它的一个很好的长处。常规树结构在添加元素和删除元素的时候都要作必定的结构调整,不然他们将可能退化为链表结构,而致使查找效率的减小。哈希树採取的是一种“见缝插针”的算法,历来不用操心退化的问题,也没必要为优化结构而採取额外的操做。所以大大节约了操做时间。
缺点
一、非排序性
哈希树不支持排序。没有顺序特性。
假设在此基础上不作不论什么改进的话并试图经过遍从来实现排序,那么操做效率将远远低于其它类型的数据结构。
关于超长字符串的问题
【关于MD5】
维基连接:http://zh.wikipedia.org/wiki/MD5
二、easy计算:从原数据计算出MD5值很是easy。
三、抗改动性:对原数据进行不论什么改动,哪怕仅仅改动1个字节。所获得的MD5值都有很是大差异。
四、弱抗碰撞:已知原数据和其MD5值,想找到一个具备一样MD5值的数据(即伪造数据)是很困难的。
五、强抗碰撞:想找到两个不一样的数据,使它们具备一样的MD5值,是很困难的。
(1996年后被证明存在弱点。可以被加以破解,对于需要高度安全性的数据。专家通常建议改用其它算法,如SHA-1)
对于超长字符串,咱们可以用MD5算法生成一个128bit的整数。而后用RadixTree(翻看前面博客)来存储这个大整数。或者使用哈希树来存储,对于这种大整数。咱们不能简单地使用计算机的整数来作除法,而是使用程序模拟人工的除法方式来作除法并得到余数。
这样,使用MD5和选用更大的质数相结合的办法。这样就可以使得经过层次比較少的哈希树来得到对keyword区间的完整覆盖。这样就下降了比較操做的次数,并提升整体的工做效率。
应用
哈希树可以普遍应用于那些需要对大容量数据进行高速匹配操做的地方。
好比:数据库索引系统、短信息中的收条匹配、大量号码路由匹配、信息过滤匹配。
哈希树不需要额外的平衡和防止退化的操做。效率十分理想。
【參考】
http://baike.baidu.com/view/10403049.htm
http://wenku.baidu.com/view/16b2c7abd1f34693daef3e58.html