一、基本介绍
1、基本介绍
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表。
2、表的实现
数组 ~~~~ 链表的形式
3、哈希表的常用点
我们开发的程序会由写的java代码去操作数据库,但是频繁的去操作数据库性能也是很低的,所以我们有比较常见的缓存层(Redis Memcahe)产品,但是缓存层一般就用Hash来编写的,我们就自己来编写一个缓存层试一下。
二、哈希表的案例分析
1、先看一下这个题目
2、使用哈希表的上面问题问题分析
(1)表示员工的Emp类
class Emp {
private int id;
private String name;
private String address;
}
(2)表示节点的类
class EmpLinkedList {
Emp head = null;//头指针,之前链表的,没有学习过就去我主页复习一下,指向当前链表的第一个员工
//这里面肯迪有add list等方法
}
(3)表示我们的哈希表的类
class HashTable {
EmplinkedList[] empl;//这样的一个数组
//这个去调用EmpLikedList里面的add呀或者list呀,但是它自己一定会有一个散列函数(决定id对应到哪个链表)
}
3、代码实现
(1)有坑版
注意看我们在new HashTab的构造方法,里面会有个坑
package cn.mldn;
import java.util.Arrays;
public class HashTabDemo {
public static void main(String[] args) {
HashTab hashTab = new HashTab(7);
hashTab.add(new Emp(1,"郑"));
hashTab.add(new Emp(2,"world"));
hashTab.list();
}
}
//编写散列表
class HashTab {//管理多条链表
private EmpLinkedList[] empLinkedListArray;
private int size;//表示共有多少条链表
//实例化我们拿到构造器里面来
public HashTab(int size) {
this.size = size;
this.empLinkedListArray = new EmpLinkedList[size];
}
//添加雇员
public void add(Emp emp) {
//根据员工id得到该员工应该加入到哪条链表,所以编写散列函数
int empLinkedListNo = hashFun(emp.id);
//将emp添加到对应的链表中
empLinkedListArray[empLinkedListNo].add(emp);
}
//遍历方法,遍历哈希表
public void list() {
for (int i = 0; i < size; i++) {
empLinkedListArray[i].list();
}
}
//散列函数,散列函数有很多种编写方式,这里我们用取模法
public int hashFun(int id) {
return id % size;
}
}
//表示一个雇员的类
class Emp {
public int id;//现实中千万别用public啊
public String name;
public Emp next;//默认为null
public Emp(int id,String name) {
super();
this.id = id;
this.name = name;
}
}
//表示链表,会存放我们的数据
class EmpLinkedList {
//头指针,执行第一个Emp,因此就是我们这个链表是直接指向第一个Emp的
private Emp head;//默认为空
//添加雇员的方法
//1、添加雇员就是添加到最后
//2、id是自增长的
public void add(Emp emp) {
//如果添加第一个雇员
if (head == null) {
this.head = emp;
return;
}
//如果不是第一个雇员,通过一个辅助变量定位到最后
Emp current = head;
while (true) {
if (current.next == null) {//说明到最后了
break;
}
//否则后移个
current = current.next;
}
//当退出后,说明找到了,直接挂到最后即可
current.next = emp;
}
//2、遍历的方法
public void list() {
if (head == null) {//说明链表为空
System.out.println("链表为空");
return;
}
//否则打印
System.out.println("当前链表的信息为");
Emp current = head;//辅助指针
while (true) {
System.out.printf("id = %d,name = %s\t",current.id,current.name);
if (current.next == null) {//说明是最后节点
break;
}
current = current.next;//后移遍历
}
}
}
报这个错,原因是什么:因为我们在创建数组时,输入这个数组默认为零,但是我们这个数组里面要放的是链表EmplikedList类,所有这里要修改一下
(2)没坑版
package cn.mldn;
import java.util.Arrays;
public class HashTabDemo {
public static void main(String[] args) {
HashTab hashTab = new HashTab(7);
hashTab.add(new Emp(1,"郑"));
hashTab.add(new Emp(2,"world"));
hashTab.list();
}
}
//编写散列表
class HashTab {//管理多条链表
private EmpLinkedList[] empLinkedListArray;
private int size;//表示共有多少条链表
//实例化我们拿到构造器里面来
public HashTab(int size) {
this.size = size;
this.empLinkedListArray = new EmpLinkedList[size];
for (int i = 0; i < size; i++) {
empLinkedListArray[i] = new EmpLinkedList();
}
}
//添加雇员
public void add(Emp emp) {
//根据员工id得到该员工应该加入到哪条链表,所以编写散列函数
int empLinkedListNo = hashFun(emp.id);
//将emp添加到对应的链表中
empLinkedListArray[empLinkedListNo].add(emp);
}
//遍历方法,遍历哈希表
public void list() {
for (int i = 0; i < size; i++) {
empLinkedListArray[i].list();
}
}
//散列函数,散列函数有很多种编写方式,这里我们用取模法
public int hashFun(int id) {
return id % size;
}
}
//表示一个雇员的类
class Emp {
public int id;//现实中千万别用public啊
public String name;
public Emp next;//默认为null
public Emp(int id,String name) {
super();
this.id = id;
this.name = name;
}
}
//表示链表,会存放我们的数据
class EmpLinkedList {
//头指针,执行第一个Emp,因此就是我们这个链表是直接指向第一个Emp的
private Emp head;//默认为空
//添加雇员的方法
//1、添加雇员就是添加到最后
//2、id是自增长的
public void add(Emp emp) {
//如果添加第一个雇员
if (head == null) {
this.head = emp;
return;
}
//如果不是第一个雇员,通过一个辅助变量定位到最后
Emp current = head;
while (true) {
if (current.next == null) {//说明到最后了
break;
}
//否则后移个
current = current.next;
}
//当退出后,说明找到了,直接挂到最后即可
current.next = emp;
}
//2、遍历的方法
public void list() {
if (head == null) {//说明链表为空
System.out.println("链表为空");
return;
}
//否则打印
System.out.println("当前链表的信息为");
Emp current = head;//辅助指针
while (true) {
System.out.printf("id = %d,name = %s\t",current.id,current.name);
if (current.next == null) {//说明是最后节点
break;
}
current = current.next;//后移遍历
}
}
}
(3)分析一下
我这样添加:但是会给我报的是链表为空,为什么会有这样的信息呢,因为我们的数据添加编号是1和2,说明我们的第一条链表上没有数据,第二条和第三条有数据而下面没有数据
(4)完整实现版
没有删除的方法,自己可以练习一下
package cn.mldn;
import java.util.Arrays;
public class HashTabDemo {
public static void main(String[] args) {
HashTab hashTab = new HashTab(7);
hashTab.add(new Emp(1,"郑"));
hashTab.add(new Emp(2,"world"));
hashTab.list();
hashTab.findEmpById(1);
hashTab.findEmpById(5);
}
}
//编写散列表
class HashTab {//管理多条链表
private EmpLinkedList[] empLinkedListArray;
private int size;//表示共有多少条链表
//实例化我们拿到构造器里面来
public HashTab(int size) {
this.size = size;
this.empLinkedListArray = new EmpLinkedList[size];
for (int i = 0; i < size; i++) {
empLinkedListArray[i] = new EmpLinkedList();
}
}
//添加雇员
public void add(Emp emp) {
//根据员工id得到该员工应该加入到哪条链表,所以编写散列函数
int empLinkedListNo = hashFun(emp.id);
//将emp添加到对应的链表中
empLinkedListArray[empLinkedListNo].add(emp);
}
//遍历方法,遍历哈希表
public void list() {
for (int i = 0; i < size; i++) {
empLinkedListArray[i].list();
}
}
//散列函数,散列函数有很多种编写方式,这里我们用取模法
public int hashFun(int id) {
return id % size;
}
//查找方法
public void findEmpById(int id) {
int findId = hashFun(id);
Emp empById = empLinkedListArray[findId].findEmpById(id);
if (empById != null) {
System.out.println("在" + id + "链表找到了");
System.out.println();
} else {
System.out.println("没有找到");
}
}
}
//表示一个雇员的类
class Emp {
public int id;//现实中千万别用public啊
public String name;
public Emp next;//默认为null
public Emp(int id,String name) {
super();
this.id = id;
this.name = name;
}
}
//表示链表,会存放我们的数据
class EmpLinkedList {
//头指针,执行第一个Emp,因此就是我们这个链表是直接指向第一个Emp的
private Emp head;//默认为空
//添加雇员的方法
//1、添加雇员就是添加到最后
//2、id是自增长的
public void add(Emp emp) {
//如果添加第一个雇员
if (head == null) {
this.head = emp;
return;
}
//如果不是第一个雇员,通过一个辅助变量定位到最后
Emp current = head;
while (true) {
if (current.next == null) {//说明到最后了
break;
}
//否则后移个
current = current.next;
}
//当退出后,说明找到了,直接挂到最后即可
current.next = emp;
}
//2、遍历的方法
public void list() {
if (head == null) {//说明链表为空
System.out.println("链表为空");
return;
}
//否则打印
System.out.println("当前链表的信息为");
Emp current = head;//辅助指针
while (true) {
System.out.printf("id = %d,name = %s\t",current.id,current.name);
if (current.next == null) {//说明是最后节点
break;
}
current = current.next;//后移遍历
}
}
//3、查找方法
public Emp findEmpById(int id) {
//判断是非链表为空
if (head == null) {
System.out.println("链表为空");
return null;
}
//辅助指针
Emp current = head;
while (true) {
if (current.id == id) {//找到了
System.out.printf("id = %d,name = %s\t",current.id,current.name);
break;//说明就是这个人了
}
if (current.next == null) {//说明没有找到你想要找的人
current = null;
break;
}
//否则就要往移动一个位置
current = current.next;
}
return current;
}
}