哈希表

哈希表的基本介绍

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表

哈希表(散列)-Google上机题

看一个实际需求,google公司的一个上机题:

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址..),当输入该员工的id时,要求查找到该员工的 所有信息.

要求: 不使用数据库,尽量节省内存,速度越快越好=>哈希表(散列)

思路分析

  1. 使用链表来实现哈希表, 该链表不带表头[即: 链表的第一个结点就存放雇员信息]
  2. 代码实现[增删改查(显示所有员工,按id查询)]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package com.company;


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.add(emp);
break;
case "list":
hashTab.list();
break;
case "find":
System.out.println("请输入要查找的id");
id = scanner.nextInt();
hashTab.findEmpById(id);
break;
case "delete":
System.out.println("请输入要删除的id");
id = scanner.nextInt();
hashTab.deleteEmpById(id);
break;
case "exit":
scanner.close();
System.exit(0);
default:
break;
}
}
}

}

//创建HashTab 管理多条链表
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();
}
}

//添加雇员
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 deleteEmpById(int id) {
//使用散列函数确定到哪条链表删除
int empLinkedListNO = hashFun(id);
boolean flag = empLinkedListArray[empLinkedListNO].deleteEmpById(id);
if (flag) {//找到
System.out.printf("在第%d条链表中找到 雇员 id = %d,删除成功\n", (empLinkedListNO + 1), id);
} else {
System.out.println("在哈希表中,没有找到该雇员,无法删除~");
}
}

//编写散列函数, 使用一个简单取模法
public int hashFun(int id) {
return id % size;
}


}

//表示一个雇员
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;
}
}

//创建EmpLinkedList ,表示链表
class EmpLinkedList {
//头指针,执行第一个Emp,因此我们这个链表的head 是直接指向第一个Emp
private Emp head; //默认null

//添加雇员到链表
//说明
//1. 假定,当添加雇员时,id 是自增长,即id的分配总是从小到大
// 因此我们将该雇员直接加入到本链表的最后即可
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查找雇员,如果查找到,就返回Emp, 如果没有找到,就返回null
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;
}

//根据删除雇员,如果删除成功,1, 如果没有找到,就返回0
public boolean deleteEmpById(int id) {
boolean flag = false; // 标志是否找到待删除节点的
//判断链表是否为空
if (head == null) {
System.out.println("链表为空");
return flag;
}
//辅助指针
Emp curEmp = head;

while (true) {
if (curEmp.next == null) { //已经到链表的最后
break;
}
if (curEmp.next.id == id) {
//找到的待删除节点的前一个节点temp
curEmp.next = curEmp.next.next;
flag = true;
break;
}
curEmp = curEmp.next;
}
return flag;
}
}

哈希表
http://example.com/2019/08/20/哈希表/
作者
shoukailiang
发布于
2019年8月20日
许可协议