这几天了解了一下哈希的结构,现在就将我的理解进行一下总结。首先我先解释一下什么叫做哈希函数。哈希函数说白了就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。然后我们再根据这个摘要来得到我们所放进去的数据。那么哈希的内部到底是怎么样的呢。在java中有两种基本的结构:数组和模拟指针(引用),所用的数据结构都是由这两种结构得来的。当然在java中hashMap也是由这两种结构得来的,但是相比较而言,hash的结构是比较优秀的,它能快速高效的进行查找与存储数据。现在,就hash的结构来重点讲解一下。
首先在java中,虽然我们说集合是可以直接来存储对象的,那么到底它内部是怎么存的,在我们实例化一个对象后然后调用一下对象的hashCode()方法。下面一小段代码:
public class MyHash { public static void main(String[]args){ MyHash myHash = new MyHash(); MyHash myHash1 = new MyHash(); MyHash myHash2 = new MyHash(); MyHash myHash3 = new MyHash(); int j = myHash.hashCode(); int k = myHash1.hashCode(); int l = myHash2.hashCode(); int m = myHash3.hashCode(); System.out.println("myHash的引用"+j); System.out.println("myHash1的引用"+k); System.out.println("myHash2的引用"+l); System.out.println("myHash3的引用"+m); }
通过结果我们可以看到是一串数字。那么这一串数字到底表示什么,是干嘛用的呢?其实这串
数字就是对象的引用,那么所谓的存对象就是存储这些对象的引用,然后再根据这些引用来找
到对象。那么在哈希表中到底是怎么实现对这些引用和数据的存储。前面我们已经说过了,
hash的基本结构是数组和链表的结合,那么到底是怎么实现的呢。我们有一个图来进行说明:
如图横向的是一个数组,纵向的是一个链表。我们先对一个对象的hashCode()方法得到的
一串数字进行hash()算法,然后根据所得到的key值找到在数组上相应的的位置,然后将
key-value键值对存储进去,那么如果原来的位置上有值怎么办,我们先检验一下值,然后再
根据值来决定是直接覆盖还是以链表的方式链接。说到这里可能会有这样的一个疑问,我们为
什么要用这么复杂的方式来存储数据,直接用链表或者数组不就行了吗。我们分别来讨论一下
。当使用数组来存储对象时我们要根据什么来作为缩引,如果是根据对象的引用,那么必然会
造成内存的巨大的浪费,同时当我们来声明数组是也是无法预测最大的范围。当使用链表时。
我们的确可以解决上面的索引以及内存消耗问题,但是我们每次索引一个值都要遍历整个链表
。这样必然会造成时间的大量消耗。这样hash表就能很好的解决这样的问题,但是问题又来了
。如果但我们经过hash过后的key值对应在一个数组的值上,也就是说存储在数组中的链表过
于长,那么我们就算能很好的找到key值也还是要遍历一条很长的链表才能得到数据。这样我
们又有了rehash()的方法的概念了。说白了就是当我们链表的长度超过一定的值,就重新
建立一个数组,这个数组的长度将比原来的数组的长度要大,然后在将原来数组中的所有数据
冲新hash()然后再将数据存储进去。当然rehash()是最消耗时间的。一般而言我们申明
数组的长度是会是2的n次方(具体原因自己百度),在rehash()是我们也是会将新建的数
据的长度是原来数组的2倍。
下面我将结合着自己写的hash表来讲解一下,当然我的hash表是没有系统提供的那么优化,
想要更进一步了解就自己查看源代码吧。
首先建立一个节点类
package hash; public class Node { private Object value; private Node next; public Node(){ } public Node(Object value){ this.value = value; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }
然后结合这来分析MyHash中的代码,首先是hash()函数,这里我用了比较笨的方法,
//写一下hash方法,在这里我用一种比较笨拙hash方法,直接取余数,那么这个返回值就是在数组中下标 public int hash(Object o){ int hashCode = o.hashCode(); int re = hashCode%(array.length); return re; }
然后我就写了一个向我的hash结构中加数据的方法:
//向hashSet中加数据 //把对象加入集合,不允许加入重复的元素 public void add(Object value) { //先根据value得到index int index = hash(value); //由value创建一个新节点newNode Node newNode = new Node(value); //由index得到一个节点node Node node = array[index]; //若这个由index得到的节点是空,则将新节点放入其中 if (node == null) { array[index]=newNode; size++; } else {//若不为空则遍历这个点上的链表(下一个节点要等于空或者该节点不等于新节点的值--不允许重复) Node nextNode; while (!node.getValue().equals(value) && (nextNode = node.getNext())!=null) { listSize++; node = nextNode; } //当链表遍历到最后一个节点时 if (!node.getValue().equals(value)) { node.setNext(newNode); listSize++; size++; } //在此处进行rehash的判断 if(listSize>(this.loadFactor*this.NodeNum)){ this.NodeNum = 2*this.NodeNum; listSize=0; reHash(this.NodeNum); } } }
上面的在添加数据的时候我们首先判断相应的索引位置是否有数据,如果有就先与相应链表的数据进行分析,看是否相等以及最后的添加,当添加完后我们再判断是否要进行reHash()的操作,rehash()的具体代码在下面:
//获取所有的数据,用来进行reHash(); public Object[] getAll() { Object [] values = new Object[size]; int index = 0; for (int i = 0; i < array.length; i++) { Node node = array[i]; while (node!=null) { values[index++]=node.getValue(); node = node.getNext(); } } return values; } //reHash() public void reHash(int length){ //重新定义数组长度 array = new Node[length]; Object [] values = getAll(); //将数据加到新的hash结构中 for(Object value:values){ add(value); } }
我们先根据负载因子以及数组长度来计算每个数组中链表的最大长度,如果长度过大,就进行reHash()方法,有此可见Rehash()是最耗时间的。以上的代码写的不是很好,主要是用来了解hash的结构。
相关推荐
本课件“数据结构 课件java版本”是基于Java编程语言来讲解这一主题的,旨在帮助学生和开发者深入理解数据结构的基本概念,并掌握用Java实现这些数据结构的方法。 在Java中,数据结构主要分为以下几类: 1. **数组...
Java语言程序设计是编程领域中一本深受欢迎的教材,尤其对于初学者和进阶者来说,它提供了全面而深入的Java知识。第八版的奖励章节包括了从第38章到第48章的内容,这些章节是原书的扩展部分,旨在帮助读者更深入地...
此外,还可以使用Java语言特性,如递归、循环等来实现各种算法。 ### 结论 掌握数据结构与算法不仅能够帮助开发者写出更高效、更简洁的代码,也是进入高级编程领域、参与项目开发的基础。通过阅读“Java数据结构和...
在Java编程语言中,哈希表(HashTable)是一种常见的数据结构,它提供了高效的数据存储和检索功能。哈希表基于哈希函数将键(Key)映射到数组的索引位置,通过键值对(Key-Value Pair)来存储数据。这种数据结构允许...
### 数据结构与算法(JAVA语言版) #### Java与面向对象程序设计 ...以上内容涵盖了《数据结构与算法(JAVA语言版)》书中所涉及的重要知识点,希望能帮助读者深入理解和掌握这些基本概念和技术细节。
除了`MessageDigest`,Java还提供了`java.util.hashMap`和`java.util.HashMap`类,它们是基于哈希表的数据结构,用于实现高效的键值对存储。哈希表通过哈希函数将键映射到数组的索引位置,从而实现快速的查找、插入...
【Java实现的BT协议项目源码ttorrent详解】 在IT领域,P2P(Peer-to-Peer)网络技术因其高效、分布式的...通过深入研究和实践这个项目,开发者能够更好地理解和掌握P2P网络技术,以及在Java环境中如何实现这样的系统。
google-api-translate-java(Java 语言对Google翻译引擎的封装类库) 语音识别程序 SpeechLion.tar SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来...
《Java语言深入_Equals》 Java中的`equals`方法是一个至关重要的方法,用于比较两个对象是否“相等”。在Java API规范中,`equals`方法必须遵循以下五个基本原则: 1. 对于任何引用类型,`o.equals(o)`总是返回`...
哈希计算工具 `java-hash` 是一款专为Java开发者设计的实用工具,它允许程序员方便地进行各种哈希算法的计算。...通过深入研究`java-hash`的源代码,我们可以进一步理解这些算法的实现,并可能找到优化和改进的途径。
google-api-translate-java(Java 语言对Google翻译引擎的封装类库) 语音识别程序 SpeechLion.tar SpeechLion 是一个语音识别程序,主要用来处理桌面命令,基于 Sphinx-4 语音识别引擎开发。用户可以通过该软件来...
在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...
这些Java代码示例对初学者和经验丰富的开发者都十分有价值,它们不仅提供了实践练习,也帮助理解数据结构和算法如何在实际问题中应用。通过学习和分析这些代码,开发者可以提升自己的编程技能,并更好地解决复杂的...
Java语言作为面向对象编程语言的典型代表,涵盖了丰富的编程概念和术语,本文将依据给定文件内容,详细阐述Java语言中常用方法名以及相关概念,为读者提供详细的Java知识点。 首先,“Abstractclass”和“Abstract...
### YAML详解及Java对YML的使用 #### 一、YAML简介 YAML (Yet Another Markup Language) 是一种人类可读的数据序列化格式。它旨在提供清晰且易于理解的数据表示方式,通常用于配置文件中。 #### 二、基本语法规则...
在Java编程语言中,哈希表(Hash Table)是一种常用的数据结构,它的实现通常通过`Hashtable`类。这个数据结构提供了快速的插入、删除和查找操作,其平均时间复杂度为O(1)。`Hashtable`是Java集合框架的一部分,位于...
根据提供的文件信息,“Java数据结构算法教程”似乎是一本针对初学者的书籍,旨在帮助他们理解和掌握使用Java语言实现的数据结构与算法。下面将详细展开该书可能涵盖的一些核心知识点。 ### Java 数据结构 #### 1....