前言
前面学习过的数组存储和链式存储都有一定的缺点,哈希存储结合了二者的优点。
本文源代码网址:https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/hash
https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/hash
哈希表
哈希表本质上也是数组,但是每个数组元素是结点。我们可以通过索引key快速访问到某个数据。
哈希结点
相比链表结点,增加了key
java
class Node<T>
{
int key;
T value;
Node<T> next;
public Node(int key,T value)
{
this.key=key;
this.value=value;
this.next=null;
}
}
成员变量
一个存储哈希结点的数组Node buckets[ ]。
buckets这个名字也是约定俗成。
方法
构造方法
和数组初始化一样
put存数据
我们分几种情况:
1.直接存在this.buckets[key%this.buckets.length]。
因为key可能会比buckets的长度大,所以取模操作,取模后的值为index。如果index的位置为空,直接将新结点存在该位置。
java
int index = key%this.buckets.length;
Node<T> newNode=new Node(key,num);
if(this.buckets[index]==null)
{
this.buckets[index]=newNode;
return true;
}
如果该位置原本有有效结点,又有两种情况:
2.已存在新结点key的结点,我们称为冲突,可以采用覆盖的方式,将就结点的value改为新结点的value进行覆盖。注意不可将整个结点进行覆盖。因为原结点的next指向了后面的结点,而新结点的next并没有指向下一个结点。
java
Node<T> p = this.buckets[index];
while(p.next!=null && p.key!=newNode.key)
p = p.next;
if(p.key == newNode.key) p.value = newNode.value;
3.原本没有新结点的key,把数据加在现有数据的最后即可。
java
else p.next = newNode;
put方法全代码
java
public boolean put(int key,T num)
{
int index = key%this.buckets.length;
Node<T> newNode=new Node(key,num);
if(this.buckets[index]==null)
{
this.buckets[index]=newNode;
return true;
}
Node<T> p = this.buckets[index];
while(p.next!=null && p.key!=newNode.key)
p = p.next;
if(p.key == newNode.key) p.value = newNode.value;
else p.next = newNode;
return true;
}
get取数据
通过索引key取数据,先找到对应的index结点,再一个结点一个结点往后查找,返回value。但是也可能找不到,返回null并提示。
总结
哈希存储key和value紧密相连,也叫KV存储。