哈希表(散列表)(Hashing)(顺序存储与链式存储相结合)
import java.util.Objects;
/**
* @Classname MyHashTable
* @Description hashtable的增删改查的简单实现
*/
public class MyHashTable<K, V> {
private static class Node<K, V> {
//key
K key;
//value
V value;
//哈希值
int hash;
//指向后一个结点
Node next;
public Node() {
//hash值只取决于key
this.hash = this.key == null ? 0 : this.key.hashCode();
this.next = null;
}
public Node(K key, V value) {
this.key = key;
this.value = value;
this.hash = this.key == null ? 0 : this.key.hashCode();
this.next = null;
}
}
//数组
Node<K, V>[] elements;
//元素个数
int size;
//默认容量
int capacity = 4;
//填装因子
double factor = 0.7;
public MyHashTable() {
//初始化元素个数
size = 0;
//初始化数组 ★★★★★ 记住这个写法! Node声明为静态泛型内部类
elements = (Node<K, V>[]) new Node[capacity];
}
/**
* 查
* @param key
* @return
*/
public V get(K key) {
//先计算下标值
int index = key.hashCode() % elements.length;
//对应下标位置找元素
Node<K, V> node = elements[index];
while (node != null) {
if (Objects.equals(key, node.key)) {
//找到就返回
return node.value;
}
//元素后移
node = node.next;
}
//找不到就返回null
return null;
}
/**
* 改元素
*
* @param key
* @param value
*/
public void set(K key, V value) {
//先计算下标值
int index = key.hashCode() % elements.length;
//对应下标位置找元素
Node<K, V> node = elements[index];
while (node != null) {
if (Objects.equals(key, node.key)) {
//找到就改
node.value = value;
//打印修改成功
System.out.println("修改成功");
return;
}
//元素后移
node = node.next;
}
//找不到就打印没找到
System.out.println("没找到这个元素");
}
/**
* 删除元素
*
* @param key
*/
public void remove(K key) {
//先计算下标
int index = key.hashCode() % elements.length;
//去下标位置找
Node<K, V> node = elements[index];
//父结点
Node<K, V> f = null;
while (node != null) {
//判断key是否相等
if (Objects.equals(key, node.key)) {
//只有一个结点
if (f == null && node.next == null) {
elements[index] = null;
}
//有多个结点,要删的是头节点
if (f == null && node.next != null) {
elements[index] = node.next;
}
//多个结点,但删的是中间结点
if (f != null && node.next != null) {
f.next = node.next;
}
//有多个结点,要删的是尾节点
if (f != null && node.next == null) {
f.next = null;
}
//打印删除成功
System.out.println("删除成功");
size--;
return;
}
//不相等,就往链表后面找
f = node;
node = node.next;
}
//没找到就打印个没有这个元素
System.out.println("删除失败,没找到这个元素");
}
/**
* 添加元素
*
* @param key
* @param value
*/
public void put(K key, V value) {
//判断数组是否需要扩容
if (size * 1.0 / elements.length > factor) {
//扩容
resize();
}
//把新元素放进数组中
Node<K, V> e = (Node<K, V>) new Node(key, value);
//根据hash计算下标值
int index = e.hash % elements.length;
//判断数组的这个位置是否有元素了
if (elements[index] == null) {
//没有元素,直接放
elements[index] = e;
} else {
//有元素,放到链表尾
Node<K, V> node = elements[index];
while (node.next != null) {
node = node.next;
}
node.next = e;
}
//更新size
size++;
}
/**
* 扩容数组
*/
private void resize() {
//新的capacity为旧的两倍(这里我就不考虑最大限制这些复杂情况了,只是做一个简单的实现)
int newCapacity = capacity * 2;
//创建新数组
Node<K, V>[] newEle = (Node<K, V>[]) new Node[newCapacity];
//把旧数组中的元素放到新数组中
//遍历旧数组中的元素
for (Node e : elements) {
//如果数组为空,跳过
if (e == null) continue;
//根据hash计算下标值
int index = e.hash % newEle.length;
//判断数组的这个位置是否有元素了
if (newEle[index] == null) {
//没有元素,直接放
newEle[index] = e;
} else {
//有元素,放到链表尾
Node<K, V> node = newEle[index];
while (node.next != null) {
node = node.next;
}
node.next = e;
}
}
//把新数组赋给旧数组
capacity = newCapacity;
elements = newEle;
}
public static void main(String[] args) {
MyHashTable<Integer, Integer> hash= new MyHashTable<>();
hash.put(1, 2);
hash.put(2, 9);
hash.put(3, 8);
hash.remove(1);
System.out.println(hash.size);
System.out.println(hash.get(2));
}
}
Last updated