目录
一、概述
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
二、哈希表的实际应用
三、Google上机题
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,名字,住址..),当输入该员工的id时,要求查找到该员工的所有信息。
四、Google上机题要求
-
使用链表来实现哈希表, 该链表不带表头
-
添加时,保证按照id从低到高插入。【课后思考:如果id不是从低到高插入,但要求各条链表仍是从低到高,怎么解决? 代码已实现此功能 】
-
不使用数据库,,速度越快越好=>哈希表(散列);
五、思路分析示意图
六、代码实现1 - 雇员链表【增删改查】
雇员链表类, 单条链表实现增删改查
/**
* @Description 雇员链表
* @Version V1.0
*/
public class EmpLinkedList {
// 头指针, 执行第一个Emp, 因此我们这个链表的head是直接指向第一个Emp
private Emp head;
// 有序添加雇员至链表
public void addEmpMsg(Emp emp) {
if (Optional.ofNullable(head).isEmpty()) {
head = emp;
System.out.println("雇员信息添加成功!!!");
return;
}
Emp temp = head;
Emp pri = temp; // 用于保存当前节点的前一个节点
while (true) {
if (temp.getId() > emp.getId()) {
if (head == temp) {
head = emp;
} else {
pri.setNext(emp);
}
emp.setNext(temp);
break;
}
if (Optional.ofNullable(temp.getNext()).isEmpty()) {
temp.setNext(emp);
break;
}
pri = temp;
temp = temp.getNext();
}
System.out.println("雇员信息添加成功!!!");
}
// 通过 雇员编号 查找雇员信息
public Emp getEmpMsgById(int id) {
if (Optional.ofNullable(head).isEmpty()) {
return null;
}
Emp temp = head;
while (true) {
if (Optional.ofNullable(temp.getNext()).isEmpty()) {
temp = null;
break;
}
if (temp.getId() == id) {
break;
}
temp = temp.getNext();
}
return temp;
}
// 通过 雇员编号 修改雇员信息
public void updateEmpMsgById(Emp emp) {
if (Optional.ofNullable(head).isEmpty()) {
System.out.println("链表中无成员信息!!!");
return;
}
Emp temp = head;
while (true) {
if (temp.getId() == emp.getId()) {
temp.setName(emp.getName());
System.out.println("雇员信息修改成功!!!");
break;
}
if (Optional.ofNullable(temp.getNext()).isEmpty()) {
System.out.println("当前链表中无该成员信息!!!");
break;
}
temp = temp.getNext();
}
}
// 通过 雇员编号 删除雇员信息
public void deleteEmpMsgById(int id) {
if (Optional.ofNullable(head).isEmpty()) {
System.out.println("链表中无成员信息!!!");
return;
}
Emp temp = head;
Emp pri = temp;
while (true) {
if (temp.getId() == id) {
if (temp == head) {
head = temp.getNext();
} else {
pri.setNext(temp.getNext());
}
System.out.println("雇员信息删除成功!!!");
break;
}
if (Optional.ofNullable(temp.getNext()).isEmpty()) {
System.out.println("当前链表中无该成员信息!!!");
break;
}
pri = temp;
temp = temp.getNext();
}
}
// 遍历链表
public void listEmpMsg(int node) {
if (Optional.ofNullable(head).isEmpty()) {
System.out.println("第"+(node + 1)+"条链表中无成员信息!!!");
return;
}
System.out.print("第"+(node + 1)+"条链表信息为: ");
Emp temp = head;
while (true) {
System.out.print(" =>id=" + temp.getId() + " name=" + temp.getName());
if (Optional.ofNullable(temp.getNext()).isEmpty())
break;
temp = temp.getNext();
}
System.out.println();
}
}
七、代码实现2 - 哈希表类【增删改查】
哈希表类用于管理多条链表, 并调用单条链表中的增删改查方法。通过散列函数取模法将每一位成员信息存放至指定位置
import java.util.Optional;
/**
* @Description 哈希表: 用于管理多条链表
* @Version V1.0
*/
public class HashTable {
private EmpLinkedList[] empLinkedLists;
private int size;
public HashTable(int size) {
this.size = size;
empLinkedLists = new EmpLinkedList[size];
for (int i = 0; i < size; i++) {
empLinkedLists[i] = new EmpLinkedList();
}
}
// 添加雇员信息
public void addEmpMsg(Emp emp) {
int index = hashFun(emp.getId());
empLinkedLists[index].addEmpMsg(emp);
}
// 遍历雇员信息
public void listEmpMsg() {
for (int i = 0; i < size; i++) {
empLinkedLists[i].listEmpMsg(i);
}
}
// 通过 雇员编号 查找雇员信息
public void getEmpMsgById(int id) {
int index = hashFun(id);
Emp emp = empLinkedLists[index].getEmpMsgById(id);
if (Optional.ofNullable(emp).isEmpty()) {
System.out.println("没有找到雇员信息!!!");
}else{
System.out.printf("在第%d条链表中查询到了编号为%d的雇员信息: id=%d, name=%s\n",
(index+1), id, emp.getId(), emp.getName());
}
}
// 通过 雇员编号 修改雇员信息
public void updateEmpMsgById(Emp emp) {
int index = hashFun(emp.getId());
empLinkedLists[index].updateEmpMsgById(emp);
}
// 通过 雇员编号 删除雇员信息
public void removeEmpMsgById(int id) {
int index = hashFun(id);
empLinkedLists[index].deleteEmpMsgById(id);
}
// 散列函数: 取模法, 通过雇员编号返回指定添加位
private int hashFun(int id) {
return id % size;
}
}