查找——图文翔解HashTree(哈希树)
引
在各种数据结构(线性表、树等)中,记录在结构中的相对位置是随机的。因此在机构中查找记录的时须要进行一系列和keyword的比較。这一类的查找方法建立在“比較”的基础上。查找的效率依赖于查找过程中所进行的比較次数。
之前我们介绍的各种基于比較的树查找算法,这些查找算法的效率都将随着数据记录数的增长而下降。
不过有的比較慢(时间复杂度为O(n)),有的比較快(时间复杂度是O(logn))而已。这些查找算法的平均查找长度是在一种比較理想的情况下获得的。
在实际应用其中,对数据结构中数据的频繁添加和删除将不断地改变着数据的结构。
这些操作将可能导致某些数据结构退化为链表结构,那么其性能必定将下降。
为了避免出现这样的情况而採取的调整措施。又不可避免的添加了程序的复杂程度以及操作的额外时间。
哈希表
理想的情况是希望不经过不论什么比較,一次存取便能得到所查的记录。那就必须在记的存储位置和它的keyword之间建立一个确定的相应关系f,使每一个keyword和一个唯一的存储位置相相应。因而在查找时。仅仅要依据这个相应关系f找到给定值K的像f(K)。由此,不须要进行比較便可直接取得所查记录。在此,我们称这个相应关系为哈希(Hash)函数。按这个思想建立的表为哈希表。
在哈希表中对于不同的keyword可能得到同一哈希地址,这样的现象称做冲突。在普通情况下。冲突仅仅能尽可能地降低,而不能全然避免。由于哈希函数是从keyword集合到地址集合的映像。通常keyword的集合比較大,它的元素包含全部可能的keyword。而地址集合的元素仅为哈希表中的地址值。在普通情况下,哈希函数是一个压缩映像函数。这就不可避免的要产生冲突。
哈希树(HashTree)算法就是要提供一种在理论上和实际应用中均能有效地处理冲突的方法。一般的哈希(Hash)算法都是O(1)的,并且基本是以空间换时间。这非常easy导致对存储空间无限制的需求。
本文中哈希树(HashTree)算法在实际操作中使用了一些技巧使得对空间的需求控制在一定范围内。即空间需求仅和所须要存储的对象个数有关,不会无限制地“膨胀”下去。
哈希树的理论基础
【质数分辨定理】
简单地说就是:n个不同的质数能够“分辨”的连续整数的个数和他们的乘积相等。
“分辨”就是指这些连续的整数不可能有全然同样的余数序列。
(这个定理的证明详见: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開始的连续质数创建的,即:从上到下的层级中的每一个节点中的子树个数为2、3、5、7、11、13、17、19、23、29。第一层中的每一个节点的子树个数为2,第二层中的每一个节点子树个数为5.。。。。
上图中的子树上的数字。是其父节点的子树指针数组的索引值】
查找
哈希树的节点查找过程和节点插入过程类似,就是对keyword用质数序列取余,依据余数确定下一节点的分叉路径,直到找到目标节点。
如上图,最小”哈希树(HashTree)在从4G个对象中找出所匹配的对象,比較次数不超过10次。也就是说:最多属于O(10)。在实际应用中,调整了质数的范围,使得比較次数一般不超过5次。也就是说:最多属于O(5)。
因此能够依据自身须要在时间和空间上寻求一个平衡点。
删除
哈希树的节点删除过程也非常easy。哈希树在删除的时候,并不做不论什么结构调整。
仅仅是先查到到要删除的节点,然后把此节点的“占位标记”置为false就可以(即表示此节点为空节点。但并不进行物理删除)。
长处
1、结构简单
从哈希树的结构来说。很的简单。每层节点的子节点个数为连续的质数。子节点能够随时创建。因此哈希树的结构是动态的,也不像某些哈希算法那样须要长时间的初始化过程。哈希树也没有必要为不存在的keyword提前分配空间。
须要注意的是哈希树是一个单向添加的结构,即随着所须要存储的数据量添加而增大。
即使数据量降低到原来的数量,可是哈希树的总节点数不会降低。
这样做的目的是为了避免结构的调整带来的额外消耗。
2、查找迅速
从算法过程我们能够看出,对于整数,哈希树层级最多能添加到10。
因此最多仅仅须要十次取余和比較操作,就能够知道这个对象是否存在。
这个在算法逻辑上决定了哈希树的优越性。
一般的树状结构。往往随着层次和层次中节点数的添加而导致很多其它的比較操作。操作次数能够说无法准确确定上限。而哈希树的查找次数和元素个数没有关系。假设元素的连续keyword总个数在计算机的整数(32bit)所能表达的最大范围内,那么比較次数就最多不会超过10次。通常低于这个数值。
3、结构不变
从删除算法中能够看出,哈希树在删除的时候,并不做不论什么结构调整。这个也是它的一个很好的长处。常规树结构在添加元素和删除元素的时候都要做一定的结构调整,否则他们将可能退化为链表结构,而导致查找效率的减少。哈希树採取的是一种“见缝插针”的算法,从来不用操心退化的问题,也不必为优化结构而採取额外的操作。因此大大节约了操作时间。
缺点
1、非排序性
哈希树不支持排序。没有顺序特性。
假设在此基础上不做不论什么改进的话并试图通过遍历来实现排序,那么操作效率将远远低于其它类型的数据结构。
关于超长字符串的问题
假设是超长字符串的keyword。该怎样处理?若把它们按26进制每一位都转换为数字。则得到的结果太大。
我们能够用MD5等消息压缩算法来生成定长的整数。
【关于MD5】
维基链接:http://zh.wikipedia.org/wiki/MD5
MD5(Message Digest Algorithm 消息摘要算法第五版)
一种被广泛使用的password散列函数。能够产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
MD5算法具有下面特点:
1、压缩性:随意长度的数据。算出的MD5值长度都是固定的。
2、easy计算:从原数据计算出MD5值非常easy。
3、抗改动性:对原数据进行不论什么改动,哪怕仅仅改动1个字节。所得到的MD5值都有非常大差别。
4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有同样MD5值的数据(即伪造数据)是很困难的。
5、强抗碰撞:想找到两个不同的数据,使它们具有同样的MD5值,是很困难的。
(1996年后被证实存在弱点。能够被加以破解,对于须要高度安全性的数据。专家一般建议改用其它算法,如SHA-1)
对于超长字符串,我们能够用MD5算法生成一个128bit的整数。然后用RadixTree(翻看前面博客)来存储这个大整数。或者使用哈希树来存储,对于这种大整数。我们不能简单地使用计算机的整数来做除法,而是使用程序模拟人工的除法方式来做除法并获得余数。
这样,使用MD5和选用更大的质数相结合的办法。这样就能够使得通过层次比較少的哈希树来获得对keyword区间的完整覆盖。这样就降低了比較操作的次数,并提高总体的工作效率。
应用
哈希树能够广泛应用于那些须要对大容量数据进行高速匹配操作的地方。
比如:数据库索引系统、短信息中的收条匹配、大量号码路由匹配、信息过滤匹配。
哈希树不须要额外的平衡和防止退化的操作。效率十分理想。
【參考】
http://baike.baidu.com/view/10403049.htm
http://wenku.baidu.com/view/16b2c7abd1f34693daef3e58.html
----------------------------------
查找——图文翔解HashTree(哈希树)的更多相关文章
- 查找——图文翔解Treap(树堆)
之前我们讲到二叉搜索树,从二叉搜索树到2-3树到红黑树到B-树. 二叉搜索树的主要问题就是其结构与数据相关,树的深度可能会非常大,Treap树就是一种解决二叉搜索树可能深度过大的还有一种数据结构. T ...
- 查找——图文翔解SkipList(跳跃表)
跳跃表 跳跃列表(也称跳表)是一种随机化数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作须要O(logn)平均时间). 基本上.跳跃列表是对有序的链表添加上附加的前进链接,添加是以随 ...
- HashTree(哈希树) ——和trie类似,只是将字符换成了质数,sphinx用到了???
摘自:http://blog.csdn.net/yang_yulei/article/details/46337405 哈希树的理论基础 [质数分辨定理] 简单地说就是:n个不同的质数可以" ...
- B树和B+树的插入、删除图文详解(good)
B树和B+树的插入.删除图文详解 1. B树 1. B树的定义 B树也称B-树,它是一颗多路平衡查找树.我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数 ...
- 012-数据结构-树形结构-哈希树[hashtree]、字典树[trietree]、后缀树
一.哈希树概述 1.1..其他树背景 二叉排序树,平衡二叉树,红黑树等二叉排序树.在大数据量时树高很深,我们不断向下找寻值时会比较很多次.二叉排序树自身是有顺序结构的,每个结点除最小结点和最大结点外都 ...
- 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了!
大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...
- Git学习系列之Windows上安装Git详细步骤(图文详解)
前言 最初,Git是用于Linux下的内核代码管理.因为其非常好用,目前,已经被成功移植到Mac和Windows操作系统下. 鉴于大部分使用者使用的是Windows操作系统,故,这里详细讲解Windo ...
- 最佳实战Docker持续集成图文详解
最佳实战Docker持续集成图文详解 这是一种真正的容器级的实现,这个带来的好处,不仅仅是效率的提升,更是一种变革:开发人员第一次真正为自己的代码负责——终于可以跳过运维和测试部门,自主维护运行环境( ...
- APNS推送服务证书制作 图文详解教程(新)
iOS消息推送的工作机制可以简单的用下图来概括: Provider是指某个iPhone软件的Push服务器,APNS是Apple Push Notification Service的缩写,是苹果的服务 ...
随机推荐
- MongoDB索引类型
与关系型数据库一样,合理的使用索引可以大幅提高MongoDB的查询效率,本文介绍基础索引.复合索引.文档索引等几种常用索引的使用. 1. 基础索引与复合索引 1.1 基础索引 创建索引时,可以是一个集 ...
- [na]ppp协议链路认证-chap认证流程
Point-to-Point Protocol (PPP)协议是广域网链路的一种协议,不同于局域网的ethernetII协议 PPP协商过程,分三步:LCP.认证.NCP. 一 协议概述 PPP包含以 ...
- CocoaPods did not set the base configuration of your project 问题解决方式
今天在使用pod install的时候.出现了 [!] CocoaPods did not set the base configuration of your project because you ...
- 关于 \t 水平制表符 Horizontal Tab (TAB)
今天在学learn python the hard way ex26修改的时候,有一个关于\t的问题,下面分别为代码以及输出结果: 1 poem = """ 2 \tTh ...
- Extjs combox的异步加载
很多朋友用 extjs 很多时候都要用到combo 而异步加载是用的最多的 今天我就举一个例子 了解combo的异步加载 Ext.onReady(function () { Ext.BLANK_IM ...
- Class.getName和Class.getCanonicalName的区别
对于一般的type来说,这二者没有区别,对于array和inner type,就有区别了,可以写代码亲测,如下: package simple; class Box { class Inner {} ...
- MyLocationService
package com.baidu.location.service; import android.app.Service;import android.content.Intent;import ...
- jackson2.8.4java对象序列化成json字符串格式化时间
public class User {private int id; private Date birthday; private double money; private String name; ...
- Cookie application session
•Application 对象是存储于服务器的全局变量 •Cookie 存储信息于客户端 •Session 对象用于在服务器端存储用户的信息,在用户结束会话时被清除 1.将信息写入Cookies 中/ ...
- CentOS更新163 yum源
这个脚本也没啥多大意义,只是为了自己练习着写一下bash ======================================================================= ...