这几天了解了一下哈希的结构,现在就将我的理解进行一下总结。首先我先解释一下什么叫做哈希函数。哈希函数说白了就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。然后我们再根据这个摘要来得到我们所放进去的数据。那么哈希的内部到底是怎么样的呢。在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语言描述(第3版)》是一本深入探讨数据结构和算法分析的专业书籍,它以Java编程语言为载体,详细阐述了如何高效地组织和操作大量数据,以及如何评估和比较不同算法的性能。这本书不仅涵盖了...
《数据结构与算法分析Java语言实现源码第三版》是一本深入探讨数据结构和算法的书籍,通过Java语言为载体,提供了丰富的实例代码。书中的每个类和方法都是精心设计的,旨在帮助读者理解并掌握各种核心数据结构和算法...
数据结构与算法分析是计算机科学的核心领域,Java作为一种流行的编程语言,被广泛用于实现各种数据结构和算法。这里提到的源代码集包含了多个经典的数据结构和算法实现,如排序算法、字典树、堆、平衡二叉树以及哈希...
在Java语言描述的背景下,这些源码文件提供了丰富的实践示例,帮助我们深入理解各种数据结构和算法的工作原理。以下是根据压缩包文件中的内容提炼出的一些关键知识点: 1. **链表**(Ŀ¼.doc): 链表是一种线性数据...
本课件“数据结构 课件java版本”是基于Java编程语言来讲解这一主题的,旨在帮助学生和开发者深入理解数据结构的基本概念,并掌握用Java实现这些数据结构的方法。 在Java中,数据结构主要分为以下几类: 1. **数组...
Java语言程序设计是编程领域中一本深受欢迎的教材,尤其对于初学者和进阶者来说,它提供了全面而深入的Java知识。第八版的奖励章节包括了从第38章到第48章的内容,这些章节是原书的扩展部分,旨在帮助读者更深入地...
此外,还可以使用Java语言特性,如递归、循环等来实现各种算法。 ### 结论 掌握数据结构与算法不仅能够帮助开发者写出更高效、更简洁的代码,也是进入高级编程领域、参与项目开发的基础。通过阅读“Java数据结构和...
在Java编程语言中,哈希表(HashTable)是一种常见的数据结构,它提供了高效的数据存储和检索功能。哈希表基于哈希函数将键(Key)映射到数组的索引位置,通过键值对(Key-Value Pair)来存储数据。这种数据结构允许...
《数据结构与算法分析(Java英文版)》是一本介绍如何利用Java语言处理实际问题中的数据结构和算法的专业书籍。本书由Robert Lafore编写,通过丰富的插图和浅显易懂的语言,帮助读者理解并掌握数据结构和算法的核心...
除了`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 语音识别引擎开发。用户可以通过该软件来...