1、哈希表介绍
散列表(Hashtable,也叫哈希表)
,是根据关键码值(Keyvalue)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表
。
2、问题描述
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,name),当输入该员工的id时,要求查找到该员工的所有信息.
要求
:
1)不使用数据库,速度越快越好=>哈希表(散列)
2)添加时,保证按照id从低到高插入
3)使用链表来实现哈希表,该链表不带表头 即:链表的第一个结点就存放雇员信息
3、具体实现
3.1、员工类定义
class Emp{
public int id;
public String name;
public Emp next;// 指向下一个节点
public Emp() {
}
public Emp(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
"} ";
}
}
3.2、EmpLinkedList 链表定义
class EmpLinkedList{
// 头指针
Emp head = new Emp();
// 添加员工方法,编号从小到大
public void addByOrder(Emp emp){
Emp temp = head;// 临时变量指向头指针
boolean flag = false; // 默认没有重复的id
while (true){
if (temp.next == null){
break;
}else if(temp.next.id > emp.id){
break;
}else if(temp.next.id == emp.id){
flag = true;
break;
}
// 如果都不符合,则temp后移
temp = temp.next;
}
if (flag){
System.out.printf("编号为%d的人已经存在!\n",emp.id);
}else {
// 插入到最后
emp.next = temp.next;
temp.next = emp;
}
}
// 遍历链表
public void list(int no){
if (head.next == null){
System.out.println("第"+ no +"条链表为空!不能遍历");
return;
}
Emp temp = head;
while (temp.next != null){
System.out.println(temp.next);
temp = temp.next;
}
}
// 根据id查找员工
public Emp findById(int id){
if (head.next == null){
System.out.println("第"+ id % 5 +"链表为空");
return null;
}
Emp temp = head.next;
while (temp != null){
if (temp.id == id){
return temp;
}
temp = temp.next;
}
return null;
}
}
3.3、HashTab来管理多条链表
class HashTab{
private int size;
private EmpLinkedList[] empLinkedListArray;
// 初始化
public HashTab(int size) {
this.size = size;
empLinkedListArray = new EmpLinkedList[size];
for (int i = 0; i < size; i++) {
empLinkedListArray[i] = new EmpLinkedList();
}
}
/**
* 添加员工
* @param emp
*/
public void add(Emp emp){
// 1、根据员工id 来判断添加到哪条链表中
int i = hashFun(emp.id);
// 2、将emp添加到对应的链表中
empLinkedListArray[i].addByOrder(emp);
}
/**
* 显示雇员
*/
public void list(){
// if (empLinkedListArray == null){
// System.out.println("链表为空,不能显示!");
// return;
// }
for (int i = 0; i < size; i++) {
if (empLinkedListArray[i] != null){
System.out.println("第"+i+ " 条链表遍历");
empLinkedListArray[i].list(i);
}
}
}
/**
* 根据 id 查找员工
* @param id
* @return
*/
public void findById(int id){
int i = hashFun(id);
Emp emp = empLinkedListArray[i].findById(id);
if (emp != null){
System.out.println("找到啦! 信息为:" + emp);
}else {
System.out.println("查无此人! ");
}
}
/**
* 编写散列函数,使用取模法
* @param id
* @return
*/
public int hashFun(int id){
return id % size;
}
}
3.4、主函数进行测试
public static void main(String[] args) {
HashTab hashTab = new HashTab(5);
String key = "";
Scanner scanner = new Scanner(System.in);
boolean flag = true;
while (flag){
System.out.println("a: 添加雇员");
System.out.println("l: 显示雇员");
System.out.println("f: 查找雇员");
System.out.println("e: 退出");
key = scanner.next().toLowerCase(Locale.ROOT);
switch (key){
case "a":
System.out.printf("请输入id:");
int id = scanner.nextInt();
System.out.printf("请输入姓名:");
String name = scanner.next();
hashTab.add(new Emp(id,name));
System.out.println("");
break;
case "l":
hashTab.list();
break;
case "f":
System.out.printf("请输入id:");
id = scanner.nextInt();
hashTab.findById(id);
break;
case "e":
flag = false;
break;
}
}
}
3.5、结果演示
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出
a
请输入id:2
请输入姓名:jack
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出
a
请输入id:1
请输入姓名:smith
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出
a
请输入id:5
请输入姓名:lili
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出
l
第0 条链表遍历
Emp{id=5, name='lili'}
第1 条链表遍历
Emp{id=1, name='smith'}
第2 条链表遍历
Emp{id=2, name='jack'}
第3 条链表遍历
第3条链表为空!不能遍历
第4 条链表遍历
第4条链表为空!不能遍历
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出
f
请输入id:2
找到啦! 信息为:Emp{id=2, name='jack'}
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出
f
请输入id:6
查无此人!
a: 添加雇员
l: 显示雇员
f: 查找雇员
e: 退出