哈希表
看一个实际需求,google公司的一个上机题:
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…)当输入该员工的id时,要求查找到该员工的所有信息.
要求:
不使用数据库,尽量节省内存,速度越快越好=>哈希表(散列)
哈希表的基本介绍
散列表( Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表例题:
google公司的一个上机题:
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,名字,住址…),当输入该员工的id时,要求查找到该员工所有信息.
要求:
不使用数据库,速度越快越好=>哈希表(散列)
添加时,保证按照id从低到高插入[课后思考:如果id不是从低到高插入,但要求各条链表仍是从低到高,怎么解决?
1)使用链表来实现哈希表,该链表不带表头[即:链表的第一个结点就存放雇员信息]
2)思路分析并画出示意图
3)代码实现[增删改查(显示所有员工,按id查询)]
代码实现:
package com.iswhl.hashtab;
import java.util.Scanner;
public class HashTabDemo {
public static void main(String[] args) {
HashTab hashTab = new HashTab(7);
//编写一个简单的菜单
String key;
Scanner scanner = new Scanner(System.in);
while (true){
System.out.println("add: 添加员工");
System.out.println("list: 遍历员工");
System.out.println("find: 查询员工");
System.out.println("delete: 删除员工");
System.out.println("exit: 退出系统");
key = scanner.next();
switch (key){
case "add":
System.out.println("输入员工id");
int id = scanner.nextInt();
System.out.println("输入员工姓名");
String name = scanner.next();
Emp emp = new Emp(id, name);
//使用hashtab将员工添加到链表中
hashTab.add(emp);
break;
case "list":
System.out.println("当前链表中的数据为:");
hashTab.list();
break;
case "find":
System.out.println("请输入要查询的员工id:");
id = scanner.nextInt();
hashTab.findByEmpId(id);
break;
case "delete":
System.out.println("请输入要删除的员工id:");
id = scanner.nextInt();
hashTab.deleteByEmpId(id);
break;
case "exit":
scanner.close();
System.exit(0);
break;
default:
break;
}
}
}
}
class Emp{
public int id;
public String name;
public Emp next = null;
public Emp(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "=> id=" + id +
", name=" + name;
}
}
class EmployLinkedList{
//定义链表的头节点
private Emp head = null;
//链表的添加
public void add(Emp emp){
if (head == null){//说明当前的链表为空
head = emp;
return;
}
Emp temp = head;//定义一个中间变量
while (temp.next != null){
temp = temp.next;
}
//此时的temp为当前链表的·1·最后一个
temp.next = emp;
}
//链表的查看
public void list(int i){
if (head == null){
System.out.printf("第"+(i+1)+"条链表内的数据为空\n");
return;
}
//中间变量
Emp temp = head;
while (temp != null){
System.out.printf("第"+(i+1)+"条链表内的数据为:" + temp);
temp = temp.next;
}
System.out.println();
}
//链表的查找
public Emp findByEmpId(int id){
boolean flag = false;//找到员工的标志
if (head == null){
System.out.println("当前链表为空~");
return null;
}
//中间变量
Emp curEmp = head;
while (curEmp.next != null){//通过循环可以得到,查询的员工信息
if (curEmp.id == id){
flag = true;
break;
}
curEmp = curEmp.next;
}
if (flag == false){
curEmp = null;
}
return curEmp;
}
//链表的删除
public boolean deleteByEmpId(int id){
boolean flag = false;//删除员工的标志
//中间变量
Emp curEmp = head;
while (true){//通过循环可以得到,找到要删除的员工信息
if (curEmp == null){
break;
}
if (curEmp.id == id){//找到要删除节点的前一个节点
flag = true;
System.out.println("true=====");
break;
}
curEmp = curEmp.next;
}
if (flag){
curEmp = null;
}
return flag;
}
}
class HashTab{
public EmployLinkedList[] employLinkedListArray;
public int size;//表示当前的链表数
public HashTab(int size) {
this.size = size;
this.employLinkedListArray = new EmployLinkedList[size];
//不要忘了初始化每个链表
for (int i = 0; i < size; i++) {
employLinkedListArray[i] = new EmployLinkedList();
}
}
//链表的添加
public void add(Emp emp){
int EmployNo = hashFun(emp.id);
employLinkedListArray[EmployNo].add(emp);
}
//链表的遍历
public void list(){
int index = 0;
for (EmployLinkedList e:employLinkedListArray) {
e.list(index);
index++;
}
}
//散列函数
public int hashFun(int id){
return id % size;
}
//链表的查询
public void findByEmpId(int id){
int EmployNO = hashFun(id);//查询该用户被分配到了,哪个链表
Emp byEmpId = employLinkedListArray[EmployNO].findByEmpId(id);
if (byEmpId == null){
System.out.println("当前链表中没有该员工的信息~");
}else {
System.out.printf("当前员工在第%d条链表中 员工信息为%s\n",(EmployNO+1),byEmpId.toString());
}
}
//链表的删除
public void deleteByEmpId(int id){
int EmployNO = hashFun(id);//查询该用户被分配到了,哪个链表
boolean delete = employLinkedListArray[EmployNO].deleteByEmpId(id);
if (delete){
System.out.println("员工信息删除成功");
}else {
System.out.println("没有找到要删除的员工信息");
}
}
}