哈希树总结-java版

article/2025/10/4 21:32:26

目录

哈希树的理论基础

质数分辨定律

余数分辨定理

哈希树简介

查找

删除

优点

缺点

哈希树的java实现

节点

哈希树

哈希树的应用


哈希树的理论基础

质数分辨定律

 这个定理可以简单的表述为:n个不同的质数可以“分辨”的连续整数的个数和他们的乘积相等。“分辨”就是指这些连续的整数不可能有完全相同的余数序列。这个为哈希树的分辨方式奠定了理论基础。

显然,这个定理的一个特殊情况就是为从2起的连续质数。我们可以记为前个连续质数的乘积。连续10个质数就可以分辨大约个数,已经超过计算机中常用整数(32bit)的表达范围。

而按照目前的CPU水平,100次取余的整数除法操作几乎不算什么难事。在实际应用中,整体的操作速度往往取决于节点将关键字装载内存的次数和时间。一般来说,装载的时间是由关键字的大小和硬件来决定的;在相同类型关键字和相同硬件条件下,实际的整体操作时间就主要取决于装载的次数。他们之间是一个成正比的关系。

余数分辨定理

这个定理可以简单的表述为:n个不同的数可以“分辨”的连续整数的个数不超过他们的最小公倍数。超过这个范围就意味着冲突的概率会增加。定理1是定理2的一个特例。

哈希树简介

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

我们选择质数分辨算法来建立一颗哈希树。选择从2开始的连续质数来建立一个十层的哈希树(因为已经超过了计算机中常用整数的表达范围)。第一层节点为根节点,根节点下有2个节点;第二层的每个节点下有3个节点;依此类推,即每层节点的子节点数目为连续的质数。到了第十层,每个节点下有29个节点。

同一结点中的子结点,从左到右代表不同的余数结果。
例如:第二层结点下有三个子节点。那么从左到右分别代表:除3余0,除3余1,除3余2.
对质数进行取余操作得到的余数决定了处理的路径。

也就是说如果有21亿个数字的话,我们查找的哪怕是最底层的也仅仅需要计算10次就能找到对应的数字。

所以hash树是一棵为查找而生的树。       

查找

哈希树的节点查找过程和节点插入过程类似,就是对关键字用质数序列取余,根据余数确定下一节点的分叉路径,直到找到目标节点。
如上图,最小”哈希树(HashTree)在从4G个对象中找出所匹配的对象,比较次数不超过10次。也就是说:最多属于O(10)。在实际应用中,调整了质数的范围,使得比较次数一般不超过5次。也就是说:最多属于O(5)。因此可以根据自身需要在时间和空间上寻求一个平衡点。

删除

哈希树的节点删除过程也很简单,哈希树在删除的时候,并不做任何结构调整。
只是先查到到要删除的节点,然后把此节点的“占位标记”置为false即可(即表示此节点为空节点,但并不进行物理删除)。

优点

结构简单

从哈希树的结构来说,非常的简单。每层节点的子节点个数为连续的质数。子节点可以随时创建。因此哈希树的结构是动态的,也不像某些哈希算法那样需要长时间的初始化过程。哈希树也没有必要为不存在的关键字提前分配空间。
需要注意的是哈希树是一个单向增加的结构,即随着所需要存储的数据量增加而增大。即使数据量减少到原来的数量,但是哈希树的总节点数不会减少。这样做的目的是为了避免结构的调整带来的额外消耗。

查找迅速

从算法过程我们可以看出,对于整数,哈希树层级最多能增加到10。因此最多只需要十次取余和比较操作,就可以知道这个对象是否存在。这个在算法逻辑上决定了哈希树的优越性。
一般的树状结构,往往随着层次和层次中节点数的增加而导致更多的比较操作。操作次数可以说无法准确确定上限。而哈希树的查找次数和元素个数没有关系。如果元素的连续关键字总个数在计算机的整数(32bit)所能表达的最大范围内,那么比较次数就最多不会超过10次,通常低于这个数值。

结构不变

从删除算法中可以看出,哈希树在删除的时候,并不做任何结构调整。这个也是它的一个非常好的优点。常规树结构在增加元素和删除元素的时候都要做一定的结构调整,否则他们将可能退化为链表结构,而导致查找效率的降低。哈希树采取的是一种“见缝插针”的算法,从来不用担心退化的问题,也不必为优化结构而采取额外的操作,因此大大节约了操作时间。

缺点

非排序性

哈希树不支持排序,没有顺序特性。如果在此基础上不做任何改进的话并试图通过遍历来实现排序,那么操作效率将远远低于其他类型的数据结构。

哈希树的java实现

节点

package datastructure.tree.hashtree;import java.util.Arrays;public class Node {//node的下一层的节点public Node[] next;//节点的值public int value;//节点是否已被删除public boolean isDel;public Node(int value,int nextNum){this.value=value;this.next=new Node[nextNum];this.isDel=false;}@Overridepublic String toString() {return "Node [next=" + Arrays.toString(next) + ", value=" + value + ", isDel=" + isDel + "]";}}

哈希树

如何操作都在注释中

基本思路就是先处理root,然后处理下一层的节点,然后再跳到下一层去

package datastructure.tree.hashtree;public class HashTree {public static final int[] primeNumber=new int[]{2,3,5,7,11,13,17,19,23,29};//连续11个质数能表示6464693230个数字Node root;/**HashTree初始化* 对根节点的值设置成0,但是被删除的节点*/public HashTree(){root=new Node(0, primeNumber[0]);root.isDel=true;}/** 在HashTree中插入一个节点* @param value 节点的值*/public void insertNode(int value){//如果HashTree中已经有这个节点,就不插入if(searchNode(value)){return;}		//排除root节点被删除或者初始化的情况if(root.isDel==true){root.value=value;root.isDel=false;return;}//层级,在每一层,primeNumber[level]为下一层的节点数int level=0;				Node nowNode=root;while(true){//得到下个节点的位置(因为已经考虑了root,可以直接考虑下一层的情况)int index=value%(primeNumber[level]);			if(nowNode.next[index]==null){//在第n层,primeNumber[level]为n+1层的节点数,primeNumber[level+1]为n+2层的节点数//在第n层nowNode.next[index]为第n+1层的节点,它的next的数量为n+2层的节点数nowNode.next[index]=new Node(value, primeNumber[level+1]);break;}//将被删除的节点更新为当前值if(nowNode.next[index].isDel==true){nowNode.next[index].value=value;nowNode.next[index].isDel=false;break;}//到下一个对应节点nowNode=nowNode.next[index];level++;			}	}/**在HashTree中查询节点是否存在* @param value 节点的值* @return 存在,返回true  不存在,返回false*/public boolean searchNode(int value){//考虑root是查找节点if(root.value==value&&root.isDel==false){return true;}//层级,在每一层,primeNumber[level]为下一层的节点数int level=0;				Node nowNode=root;while(true){//得到下个节点的位置(因为已经考虑了root,可以直接考虑下一层的情况)int index=value%(primeNumber[level]);//如果对应节点为空,直接返回falseif(nowNode.next[index]==null){return false;}//如果对应节点没有被删除而且值相同,直接返回falseif(nowNode.next[index].isDel==false&&nowNode.next[index].value==value){return true;}//到下一个对应节点nowNode=nowNode.next[index];level++;			}	}/**在HashTree中删除值为value的节点* @param value 节点的值* @return 如果删除成功,返回true   如果HashTree中没有这个节点或者已经被删除,返回false*/public boolean deleteNode(int value){//考虑root是被删除节点if(root.value==value&&root.isDel==false){root.isDel=true;return true;}//层级,在每一层,primeNumber[level]为下一层的节点数int level=0;				Node nowNode=root;while(true){//得到下个节点的位置(因为已经考虑了root,可以直接考虑下一层的情况)int index=value%(primeNumber[level]);//如果对应节点为空,直接返回falseif(nowNode.next[index]==null){return false;}//如果对应节点没有被删除而且值相同,进行删除,返回trueif(nowNode.next[index].isDel==false&&nowNode.next[index].value==value){nowNode.next[index].isDel=true;return true;}//到下一个对应节点nowNode=nowNode.next[index];level++;			}	}}

测试

package datastructure.tree.hashtree;public class Main {public static void main(String[] args) {HashTree tree=new HashTree();System.out.println(tree.root);tree.insertNode(2);tree.insertNode(3);tree.insertNode(4);tree.insertNode(4);System.out.println(tree.root);System.out.println(tree.searchNode(3));tree.deleteNode(3);System.out.println(tree.root);System.out.println(tree.searchNode(3));System.out.println(tree.searchNode(2));System.out.println(tree.searchNode(4));}}

哈希树的应用

  从上面的分析可以看出哈希树是一种可以自适应的树。通过给出足够多的不同质数,我们总可以将所有已经出现的关键字进行区别。而质数本身就是无穷无尽的。这种方式使得关键字空间和地址空间不再是压缩对应方式,而是完全可以等价的。

哈希树可以广泛应用于那些需要对大容量数据进行快速匹配操作的地方。例如:数据库索引系统、短信息中的收条匹配、大量号码路由匹配、信息过滤匹配。程序员可以利用各种代码来实现哈希树结构。它可以为程序员提供一种使用起来更加方便,更加简单的快速数据存储方式。


http://chatgpt.dhexx.cn/article/Pui67Vna.shtml

相关文章

哈希树的python实现

一、问题的背景 给定一组商品购买信息,找到商品购买中频繁出现的商品集。比如说,我们有如下的商品交易信息: 市场购物信息 TipItems1Bread, Milk2Bread, Diaper, Beer, Egg3Milk, Diaper, Beer, Coke4Bread, Milk, Diaper, Beer5Bread, Milk,…

哈希列表、哈希链、哈希树

通过哈希算法检验大量数据(比如大量文件)的一致性时,常见的存储方案: 哈希列表(Hash List) 原理: 计算每个数据的哈希值,保存为一个列表。记录该列表的哈希值,用于检验…

哈希树

哈希树: 哈希树(HashTree)算法就是要提供一种在理论上和实际应用中均能有效地处理冲突的方法。一般的哈希(Hash)算法都是O(1)的,而且基本是以空间换时间。这很容易导致对存储空间无限制的需求。本文中哈希树(HashTree)算法在实际操作中使用了一些技巧使…

哈希树 (HashTree)

在讲hash树之前首先我们来理解一下质数分辨定理。 什么是质数分辨定理? 什么是质数 : 即只能被 1 和 本身 整除的数。 为什么用质数:因为N个不同的质数可以 ”辨别“ 的连续整数的数量,与这些质数的乘积相同。 百度文库解答&#…

Merkle树介绍

默克尔树(Merkle树)又叫哈希树,是区块链数据存储运用到的一个重要的技术算法。 简单来说,哈希树(默克尔树)中,每个节点都标有一个数据块的加密哈希值。哈希树可以用来验证任何一种在计算机中和计…

Merkle Tree(默克尔树)算法解析

Merkle Tree概念 Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树。Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值。非叶节点是其对应子节点串联字符串的hash。[1] 1、Hash Hash是一个把任意长…

js中的var是什么意思

js中的var是定义变量的意思,使用和不使用var都能定义变量,但是两个变量的作用域不同。 (1)在函数中和函数外分别用var定义一个变量a,函数外的变量a是全局变量,函数内的变量a是局部变量,所以在函…

python中的var是什么什么的缩写_var是什么意思

展开全部 VAR是英文Video Assistant Referee的缩写,也被称作“视频助理裁判”,由现役裁判员担任,他的职责是通过回放视频向裁e5a48de588b63231313335323631343130323136353331333366303733判员提供信息,协助裁判员纠正改变比赛走…

var 作用域||变量

平常我们在使用js 的时候一般使用var来声明变量,相比于C语言Java当中的声明变量要简单一些,但是简单肯定也会有简单的不好之处。 一般来讲,在函数内部(local variable)中,js初始化变量加var的为局部变量不加…

第一讲:var的使用

目录 使用var声明变量 不使用var,直接给变量赋值 变量的作用域 全局变量和局部变量的混用 变量提升 总结 javascript中,使用var声明变量,看似简单易学,其实不然。 在我接触的许多编程语言中,如c, c#, vb, java, p…

let与var的区别

前端小白刚学习JavaScript接触到变量的时候可能会有点懵,那就是什么时候该用let,什么时候该用var,这里给大家一个最简单,最明了的答案,看完就能明白。 首先,let是拥有块级作用域的,什么是块级作…

val和var的区别

美图欣赏: 一.背景 学习过程中,会有很多小的并且容易混淆知识点,因此会把它记录下来。 二.val(value)和var(variable)的区别 基本语法: var|val 变量名 : 变量类型 变量值1.使用var或者val定义一个变量。 使用var(variable)声…

var

在函数中&#xff0c;使用var声明的变量&#xff0c;为局部变量&#xff0c;只能在函数内部访问。 不使用var声明的变量&#xff0c;为全局变量&#xff0c;在函数外边也能访问。 没有var的情况 <script type"text/javascript">a 10;function demo() {console…

VaR如何计算?VaR计算方法

VaR方法提出的背景 传统的ALM(Asset-Liability Management,资产负债管理)过于依赖报表分析&#xff0c;缺乏时效性&#xff1b;利用方差及β系数来衡量风险太过于抽象&#xff0c;不直观&#xff0c;而且反映的只是市场&#xff08;或资产&#xff09;的波动幅度&#xff1b;而…

Matlab画线实例图

1 plot画线 直线&#xff1b; 设置线宽和颜色&#xff1b; 黄色&#xff0c;8像素宽&#xff1b; 直线&#xff0c;黄色&#xff1b; 2 line 画线 画的是坐标(1,3)到(2,4)的一条线&#xff1b; 设置线型和颜色&#xff1b; 3 数学曲线 另一个&#xff1b;

matlab 绘制三维空间直线

绘制三维空间直线 clc,clear; x-2:0.1:2; y(-17*x9)/9; z(-7*x7)/9; plot3(x,y,z,m); grid on

Matlab图像线条绘制

1.线型 定义符---:-.线型实线&#xff08;缺省值&#xff09;划线点线点划线 2.线条宽度 指定线条的宽度&#xff0c;取整为整数&#xff08;单位为像素&#xff09;。 3.线条颜色 定义符r(red)g(green)b(blue)c(cyan)颜色红色绿色蓝色青色 定义符m(magenta)y(yellow)k(bla…

matlab绘制垂线(x轴或y轴)

使用line函数就可以绘制垂线 1、绘制垂直于x轴的垂线 line([xvalue xvalue],[y1 y2])&#xff1b; 比如绘制x5 y取值为[0,10]&#xff1b; line([5 5],[0 10]); 2、绘制垂直于y轴的垂线 line([x1 x2], [yvalue yvalue])&#xff1b; 比如绘制y5 x取值为[0,10]&#xff…

由两点坐标如何画出直线 matlab

由两点坐标如何画出直线 方法1&#xff1a;利用直线方程 斜率加截距 方法2&#xff1a;数据拟合 1 %由两点坐标得数据拟合直线与画线 2 x [1,2];3 y [5,8];4 k ((8-2)/(5-1));% 由两点坐标得到直线斜率5 line k*x0.5;% 直线方程6 7 xy 1:10;% 定义画线的 x 长度8 line1 …

matplotlib画直线

使用matplotlib画两条直线&#xff1a; Code : from matplotlib.lines import Line2D import matplotlib.pyplot as pltfigure, ax plt.subplots() # 设置x&#xff0c;y值域 ax.set_xlim(left0, right20) ax.set_ylim(bottom0, top10) # 两条line的数据 line1 [(1, 1), (5…