作用:
1.解决压缩可选值的索引冲突问题
2.解决由于开放地址法的先插入数据占据后插入数据的索引位置问题
一:什么是链地址法
在哈希表每个单元中设置链表.某个数据项的关键字还是像通常一样映射到哈希表的单元中,而数据项本身插入到单元的链表中
二:代码实现
1.创建链表节点Node
public class Node {
//数据域
Person data;
//指针域
Node next;
public Node(Person person){
this.data = person;
}
}
2.链表LinkList
//链表
public class LinkList {
//头节点
private Node first;
public LinkList(){
first = null;
}
//插入节点,在头节点插入
public void insert(Person person){
Node node = new Node(person);
node.next = first;
first = node;
}
//删除头节点
public Node deleteFirst(){
Node tmp = first;
first = tmp.next;
return tmp;
}
//查找节点
public Node find(String key){
Node current = first;
//当 key 和 链表里面数据的 key 不相等的时候
// 注意: 使用key.equals(current.data.getKey()) 是因为传入的key不会是null,不会发生空指针异常
// 如果是current.data.getKey().equal(key) 则可能会抛出空指针异常
while (!key.equals(current.data.getKey())){
//到底了还没找到
if (current.next == null){
return null;
}
current = current.next;
}
return current;
}
//删除节点
public Node delete(String key){
//当前节点
Node current = first;
//当前节点的上一个节点
Node pre = first;
//先查找节点
while (!key.equals(current.data.getKey())){
//到底了还没找到
if (current.next == null){
return null;
}
// pre 用于记录当前节点的父节点
pre = current;
current = current.next;
}
//删除节点
if (current == first){
first = first.next;
}else{
pre.next = current.next;
}
return current;
}
}
3.JavaBean
public class Person {
private String key;
private String name;
public Person(String key, String name) {
this.key = key;
this.name = name;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4.HashTable
import java.math.BigInteger;
public class HashTable {
//数组
private LinkList[] arr;
//构造
public HashTable() {
arr = new LinkList[10];
}
public HashTable(int size){
arr = new LinkList[size];
}
//链地址发进行插入数据
public void insert(Person person){
//关键字
String key = person.getKey();
//获取哈希函数得到的索引
int index = hashCode(key);
//判断
//首次插入数据,链表为null
if (arr[index] == null){
//需要创建一个链表存进数组中
arr[index] = new LinkList();
}
//往链表中插入数据
arr[index].insert(person);
}
//查找数据
public Person find(String key){
int index = hashCode(key);
//直接查找数组里面的节点的数据
Node node = arr[index].find(key);
if (node == null){
return null;
}
return arr[index].find(key).data;
}
//删除数据
public Person delete(String key){
int index = hashCode(key);
return arr[index].delete(key).data;
}
//字符串转化成ASCII码,并且进行幂的连乘,最后取模再返回
//使用 BigInteger 类型代替int类型
public int hashCode(String key){
BigInteger hashCode = new BigInteger("0");
BigInteger pow = new BigInteger("1");
for (int i = key.length()-1;i>= 0 ; i--){
BigInteger value = new BigInteger(String.valueOf(key.charAt(i) - 96));
hashCode = hashCode.add(value.multiply(pow));
pow = pow.multiply(new BigInteger("27"));
}
//取模后再转成 int 类型返回
return hashCode.mod(new BigInteger(String.valueOf(arr.length))).intValue();
}
}
5.测试
public class Test {
public static void main(String[] args) {
HashTable hashTable = new HashTable();
//插入数据
hashTable.insert(new Person("a","张三"));
hashTable.insert(new Person("ct","李四"));
//对比不同key之间的数组索引
System.out.println(hashTable.hashCode("a")); //1
System.out.println(hashTable.hashCode("ct")); //1
//查找
System.out.println(hashTable.find("a").getName()); //张三
System.out.println(hashTable.find("ct").getName()); //李四
//删除数据
System.out.println(hashTable.delete("a").getName()); //张三
//查找
Person person = hashTable.find("a");
if (person == null){
System.out.println("已被删除,找不到"); // 已被删除,找不到
}else{
System.out.println(person.getName());
}
}
}