本案例通过链地址法来解决Hash冲突
实现过程
- 建立节点实体类
- 其中有一个
next
属性,用于在插入链表之后指向下一个元素
- 其中有一个
- 建立一个链表类
- 给定一个空的头节点,当有新的数据进来的时候就把这个头结点覆盖
- 如果判断头节点为空,则当前链表都为空
- 建立一个哈希表类
- 这个哈希表是一个每个元素都是链表类的数组
- 在实例化这个哈希表的时候,循环一遍数组,把每个位置的链表都初始化一遍
- **插入元素:**在插入元素的时候,先把实体类
id
传进stuHashCode
方法里,根据规则获取一个哈希编码(这里用的是模运算),然后在数组中找到这个哈希编码的位置,将元素加入链表的最后一个 - **查找元素:**遍历一遍数组,每到一个位置都继续遍历里面的那个链表
- 建立测试类
- 在测试类中实例化哈希表的同时指定哈希表数组长度
- 创建一些测试的实体类对象
- 手动模拟哈希冲突
- 通过查看哈希表内的元素可以看到冲突位置的数据已经通过链表进行存放了
代码实现
1. 实体类
package com.xiaohuowa.myhsah;
/**
* @author 小火娃
* @project_name: my_project
* @package_name: com.xiaohuowa.myhsah
*/
public class Student {
public int id;
public String name;
// 用于指向链表的下一个元素
public Student next;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
2. 链表类
package com.xiaohuowa.myhsah;
/**
* @author 小火娃
* @project_name: my_project
* @package_name: com.xiaohuowa.myhsah
*/
public class HashLinked {
public Student head = null;
/**
* 在链表中添加一个节点
* @param student 新节点
*/
public void add(Student student) {
if (head == null) {
head = student;
return;
}
// 如果链表的第一个元素非空,说明链表里已经有元素了,
// 那就遍历一遍,找到最后的元素,把新元素追加到它后面
Student stuTemp = head;
while (true) {
if (stuTemp.next == null) {
stuTemp.next = student;
return;
}
stuTemp = stuTemp.next;
}
}
/**
* 查看一个链表中的数据
* @param no 仅用于记录链表编号
*/
public void list(int no){
if (head == null) {
System.out.println("第"+no+"个链表是空链表");
}else{
Student stuTemp = head;
System.out.print("第"+no+"个链表数据 >>> ");
while (true) {
if (stuTemp == null) {
System.out.println();
return;
}
System.out.print("id: "+stuTemp.id+" name: "+stuTemp.name + " ");
stuTemp = stuTemp.next;
}
}
}
/**
* 通过id找学生
* @param id 学生id
* @return 找到返回学生对象,找不到返回空
*/
public Student getStuById(int id){
Student stuTemp = head;
while (true) {
// 如果找到了学生就返回学生对象
if (stuTemp.id == id) {
return stuTemp;
}
// 如果没找到的话就返回空
if (stuTemp.next == null) {
return null;
}
// 往后遍历
stuTemp = stuTemp.next;
}
}
}
3. 哈希表
package com.xiaohuowa.myhsah;
/**
* @author 小火娃
* @project_name: my_project
* @package_name: com.xiaohuowa.myhsah
*/
public class HashTable {
public HashLinked[] hashLinked;
public int size;
public HashTable(int size) {
this.size = size;
hashLinked = new HashLinked[size];
// 在初始化的时候,将数组中的元素初始化一遍
for (int i = 0; i < size; i++) {
hashLinked[i] = new HashLinked();
}
}
/**
* 插入学生数据,调用 stuHashCode 方法来获取哈希编码(存在数组的哪个位置的链表内)
* @param student 学生对象
*/
public void add(Student student) {
int loc = stuHashCode(student.id);
hashLinked[loc].add(student);
}
/**
* 通过模运算来获得哈希编码
* @param id 学生id
* @return 哈希编码
*/
public int stuHashCode(int id) {
return id % size;
}
/**
* 查看整个哈希表内的全部数据
*/
public void list(){
for (int i = 0; i < size; i++) {
hashLinked[i].list(i);
}
}
}
4. 测试类
package com.xiaohuowa.myhsah;
/**
* @author 小火娃
* @project_name: my_project
* @package_name: com.xiaohuowa.myhsah
*/
public class HashTest {
public static void main(String[] args) {
// 实例化哈希表,指定数组长度
HashTable hashTable = new HashTable(8);
Student stu1 = new Student(1, "张三");
Student stu2 = new Student(2, "李四");
Student stu3 = new Student(3, "王五");
Student stu4 = new Student(4, "赵六");
Student stu5 = new Student(5, "七七");
Student stu6 = new Student(6, "叭叭");
// 模拟哈希冲突
Student stu66 = new Student(14, "叭叭2号");
hashTable.add(stu1);
hashTable.add(stu2);
hashTable.add(stu3);
hashTable.add(stu4);
hashTable.add(stu5);
hashTable.add(stu6);
hashTable.add(stu66);
hashTable.list();
}
}