哈希表介绍
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表的优点
我们先前所学的数组和链表都有优缺点:
数组的特点是:寻址容易,插入和删除困难;
链表的特点是:寻址困难,插入和删除容易。
而哈希表综合两者的特性,是一种寻址容易,插入删除也容易的数据结构。
哈希表图例
简单的理解哈希表就是一个数组中的每个元素都是一个链表,链表中存放着需要存储的信息。
用到散列函数去判断信息该放在数组中的哪个链表即可,散列函数的作用实现请看案例实现。
哈希表简单实现
简单案例
简单理解之后我们来看一道题目
题目解析
1 创建一个定义员工信息的类
2 创建一个链表的实现类,实现增删改查功能。
3 创建一个数组类,散列函数的方法实现在该类中定义
代码实现
先创建一个员工信息类,偷懒只定义了id和姓名
class Emp {
public int id;
public String name;
public Emp next; // next 默认为 null
public Emp(int id, String name) {
super();
this.id = id;
this.name = name;
}
}
创建一个链表的实现类,实现增删改查功能
// 头指针,执行第一个Emp,因此我们这个链表的head 是直接指向第一个Emp
private Emp head; // 默认null
// 添加雇员到链表
public void add(Emp emp) {
// 如果是添加第一个雇员
if (head == null) {
head = emp;
return;
}
// 如果不是第一个雇员,则使用一个辅助的指针,帮助定位到最后
Emp curEmp = head;
while (true) {
if (curEmp.next == null) {// 说明到链表最后
break;
}
curEmp = curEmp.next; // 后移
}
// 退出时直接将emp 加入链表
curEmp.next = emp;
}
// 遍历链表的雇员信息
public void list(int no) {
if (head == null) { // 说明链表为空
System.out.println("第 " + (no + 1) + " 链表为空");
return;
}
System.out.print("第 " + (no + 1) + " 链表的信息为");
Emp curEmp = head; // 辅助指针
while (true) {
System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);
if (curEmp.next == null) {// 说明curEmp已经是最后结点
break;
}
curEmp = curEmp.next; // 后移,遍历
}
System.out.println();
}
// 根据id查找雇员
public Emp findEmpById(int id) {
// 判断链表是否为空
if (head == null) {
System.out.println("链表为空");
return null;
}
// 辅助指针
Emp curEmp = head;
while (true) {
if (curEmp.id == id) {// 找到
break;// 这时curEmp就指向要查找的雇员
}
// 退出
if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员
curEmp = null;
break;
}
curEmp = curEmp.next;// 以后
}
return curEmp;
}
// 删除雇员信息
public void delete(int id) {
Emp curEmp = head;
boolean flag = false;
// 刪除链表第一个节点
if (curEmp.id == id ) {
System.out.printf("已經删除 id為%d,姓名為%s \n", id,curEmp.name);
head = curEmp.next;
return;
}
//要删除的节点不是第一个节点
while (true) {
// 没有找到要删除的节点
if (curEmp.next == null) {
break;
}
// 找到删除节点
else if(curEmp.next.id == id) {
flag = true;
break;
}
curEmp = curEmp.next;
}
if (flag) {
System.out.printf("已經删除 id為%d,姓名為%s \n", id,curEmp.next.name);
curEmp.next = curEmp.next.next;
} else {
System.out.printf("要删除id為 %d 不存在\n", id);
}
}
// 修改雇员信息
public void update(int id, String name) {
// 判断链表是否为空
if (head == null) {
System.out.println("链表为空");
return;
}
// 辅助指针
Emp curEmp = head;
while (true) {
if (curEmp.id == id) {// 找到
curEmp.name = name;
break;// 这时curEmp就指向要查找的雇员
}
// 退出
if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员
curEmp = null;
break;
}
curEmp = curEmp.next;// 以后
}
}
}
创建一个数组类,散列函数的方法实现在该类中定义
class HashTab {
private EmpLinkedList[] empLinkedListArray;
private int size; // 表示有多少条链表
// 构造器,
public HashTab(int size) {//数组长度又用户决定
this.size = size;
// 初始化empLinkedListArray
empLinkedListArray = new EmpLinkedList[size];
for (int i = 0; i < size; i++) {
empLinkedListArray[i] = new EmpLinkedList();
}
}
// 编写散列函数, 使用一个简单取模法
/*
*如果id为2,2取余size后的值就是存放在数组对应值的下标。
*即id为2应放在数组下标为2的链表处
*/
public int hashFun(int id) {
return id % size;
}
// 添加雇员
public void add(Emp emp) {
// 根据员工的id ,得到该员工应当添加到哪条链表
int empLinkedListNO = hashFun(emp.id);
// 将emp 添加到对应的链表中
empLinkedListArray[empLinkedListNO].add(emp);
}
// 遍历所有的链表,遍历hashtab
public void list() {
for (int i = 0; i < size; i++) {
empLinkedListArray[i].list(i);
}
}
// 根据输入的id,查找雇员
public void findEmpById(int id) {
// 使用散列函数确定到哪条链表查找
int empLinkedListNO = hashFun(id);
Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);
if (emp != null) {// 找到
System.out.printf("在第%d条链表中找到 雇员 id = %d\n", (empLinkedListNO + 1), id);
} else {
System.out.println("在哈希表中,没有找到该雇员~");
}
}
//输入id删除雇员
public void delete(int id) {
int empLinkedListNO = hashFun(id);
empLinkedListArray[empLinkedListNO].delete(id);
}
//输入id,修改雇员名字
public void update(int id, String name) {
int empLinkedListNO = hashFun(id);
empLinkedListArray[empLinkedListNO].update(id, name);
}
}
最后在Demo类的主方法中调用即可。
public class HashTabDemo {
public static void main(String[] args) {
// 创建哈希表
HashTab hashTab = new HashTab(7);
Emp emp1 = new Emp(4, "张三");
Emp emp2 = new Emp(2, "李四");
Emp emp3 = new Emp(9, "王五");
Emp emp4 = new Emp(31, "苏七");
hashTab.add(emp1);
hashTab.add(emp2);
hashTab.add(emp3);
hashTab.add(emp4);
hashTab.list();
System.out.println("______________________________");
hashTab.findEmpById(4);
//hashTab.delete(9);
//hashTab.update(4, "夫斯基");
System.out.println("______________________________");
hashTab.list();
}
}
这就是我对哈希表的简单理解,如有错误敬请指出。