一、概念
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数 叫做散列表。
哈希表可以用来做缓存,将经常需要用的从数据库中查询出来,并存入hash表。供下一次使用。
二、哈希表练习题
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,名字,住址…),当输入该员工的 id 时,要求查找到该员工的所有信息.
要求:
- 不使用数据库,速度越快越好=>哈希表(散列)
- 添加后,要求各条链表内按照 id 从低到高
- 使用链表来实现哈希表, 该链表不带表头[即: 链表的第一个结点就存放雇员信息]
图解:
代码实现:
Emp类:
public class Emp {
private int no;
private String name;
private Emp next;// 指向下一个emp
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Emp getNext() {
return next;
}
public void setNext(Emp next) {
this.next = next;
}
public Emp(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Emp{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
EmpLinkedList类
public class EmpLinkedList {
private Emp head;
public Emp getHead() {
return head;
}
public void setHead(Emp head) {
this.head = head;
}
/**
* @Description: add 添加员工
* @param: [emp]
* @return: void
* @auther: zqq
* @date: 20/6/18 19:02
*/
public void add(Emp emp){
if (this.getHead() == null){ // 该链表还没有数据
head = emp;
}else {
boolean flag = false;//标识是否已经插入
Emp temp = this.getHead();
if (emp.getNo() < temp.getNo()){ //如果比第一个emp的id小
emp.setNext(temp);
this.setHead(emp);
flag = true;
}else {
while (temp.getNext() != null){
if (temp.getNo() == emp.getNo()){
System.out.println("编号为 "+emp.getNo()+" 的Emp已经存在,请重新设置");
return;
}
if (emp.getNo() < temp.getNext().getNo()){ //按照id顺序插入
emp.setNext(temp.getNext());
temp.setNext(emp);
flag = true;
break;
}
temp = temp.getNext();
}
}
if (!flag){
temp.setNext(emp);
}
}
}
/**
* @Description: show 显示该链表的所有内容
* @param: []
* @return: void
* @auther: zqq
* @date: 20/6/18 17:29
*/
public void show(){
Emp temp = this.getHead();
while (temp != null){
System.out.print(" => "+temp);
temp = temp.getNext();
}
System.out.println();
}
/**
* @Description: findEmpById 根据编号查找内容
* @param: [no]
* @return: haseTable.Emp
* @auther: zqq
* @date: 20/6/18 17:29
*/
public Emp findEmpById(int no){
Emp temp = this.getHead();
while (temp != null){
if (temp.getNo() == no){
return temp;
}
temp = temp.getNext();
}
return null;//没有找到
}
/**
* @Description: deleteEmp 根据id删除Emp
* @param: [no]
* @return: haseTable.Emp
* @auther: zqq
* @date: 20/6/18 17:30
*/
public void deleteEmp(int no){
Emp temp = this.getHead();
boolean flag = false; // 标识是否已经删除
if (temp.getNo() == no){ //如果第一个数就是要删除的数
head = temp.getNext();
System.out.println("编号为 "+no+" 删除成功");
flag = true;
}else {
while (temp != null){
if (temp.getNext().getNo() == no){
temp.setNext(temp.getNext().getNext());// 删除
System.out.println("编号为 "+no+" 删除成功");
flag = true;
break;
}
temp = temp.getNext();
}
}
if (!flag){
System.out.println("编号为 "+no+" 的不存在");
}
}
}
HashTable类:
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 < empLinkedLists.length; i++) { // 对hashtable里面的每一个EmpLinkedList初始化,不然会空指针
empLinkedLists[i] = new EmpLinkedList();
}
}
/**
* @Description: add 添加
* @param: [emp]
* @return: void
* @auther: zqq
* @date: 20/6/18 17:45
*/
public void add(Emp emp){
int hashNo = hashFun(emp.getNo());
empLinkedLists[hashNo].add(emp);
}
/**
* @Description: show 显示链表信息
* @param: []
* @return: void
* @auther: zqq
* @date: 20/6/18 18:26
*/
public void show(){
for (int i = 0; i < empLinkedLists.length; i++) {
if (empLinkedLists[i].getHead() == null){
System.out.println("第 "+ (i + 1) +" 个链表为空");
}else {
System.out.print("第 "+ (i + 1) +" 个链表:");
empLinkedLists[i].show();
}
}
}
/**
* @Description: findEmpById 通过id查找Emp
* @param: [no]
* @return: hashTable.Emp
* @auther: zqq
* @date: 20/6/18 18:27
*/
public Emp findEmpById(int no){
int hashNo = hashFun(no);
return empLinkedLists[hashNo].findEmpById(no);
}
/**
* @Description: deleteEmp 删除Emp
* @param: [no]
* @return: void
* @auther: zqq
* @date: 20/6/18 18:30
*/
public void deleteEmp(int no){
int hashNo = hashFun(no);
empLinkedLists[hashNo].deleteEmp(no);
}
/**
* @Description: hashFun 散列函数
* @param: [no]
* @return: int
* @auther: zqq
* @date: 20/6/18 17:40
*/
public int hashFun(int no){
return no % this.size;
}
}
测试:
public class TestHashTable {
public static void main(String[] args) {
HashTable hashTable = new HashTable(5);
Scanner scanner = new Scanner(System.in);
while (true){
System.out.println("show 显示员工");
System.out.println("add 添加员工");
System.out.println("delete 删除员工");
System.out.println("exit 退出系统");
String input = scanner.next();
int no;
switch (input){
case "show":
hashTable.show();
break;
case "add":
System.out.println("请输入员工id");
no = scanner.nextInt();
System.out.println("请输入员工姓名");
String name = scanner.next();
Emp emp = new Emp(no, name);
hashTable.add(emp);
break;
case "delete":
System.out.println("请输入要删除员工的id");
no = scanner.nextInt();
hashTable.deleteEmp(no);
break;
case "exit":
scanner.close();
System.exit(0);
break;
default:
break;
}
}
}
}