一----导读:

  首先要明确一个概念:哈希表不是 算法,而是一种数据结构 。

我们都知道,java代码可以操作数据库,并且从从数据库再返回数据。但是如果频繁的对数据库进行操作,效率较低且存在安全隐患,这时就诞生出了缓存产品,也就是现在常用的redis或者Memcache ,但是以前的 老程序员们没有这些产品怎么办?这时哈希表就出场了。一级缓存不够的话加二级缓存。

哈希表_数组

 

 哈希表常用的结构:

1)数组+链表

哈希表_数组_02

 

 

2)数组+二叉树

哈希表_数据库_03

 

 

 

二---代码实现哈希表

看一个实际的面试题:

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,姓名),

当输入该员工的id时,要求查找到该员工的所有信息。

要求,不使用数据库,速度越快越好

思路分析 :

哈希表_数据库_04

 

 测试代码:

1 public class HashTable {
2 public static void main(String[] args) {
3 // 创建一个hashtab
4 HashTab hashTab = new HashTab(7);
5
6 // 写一个简单菜单
7 String key = "";
8 Scanner scanner = new Scanner(System.in);
9 while (true) {
10 System.out.println("1)添加雇员");
11 System.out.println("2)显示雇员");
12 System.out.println("3)退出系统");
13 key = scanner.next();
14 switch (key) {
15 case "1":
16 System.out.println("输入id");
17 int id = scanner.nextInt();
18 System.out.println("输入名字");
19 String name = scanner.next();
20 // 创建雇员
21 Emp emp = new Emp(id,name);
22 hashTab.add(emp);
23 break;
24 case "2":
25 hashTab.list();
26 break;
27 case "3":
28 scanner.close();
29 System.exit(0);
30
31 default:
32 break;
33
34 }
35 }
36
37
38
39
40 }
41 }
42
43 // 创建HashTab 管理多条链表
44 class HashTab {
45 private EmpLinkedList[] empLinkedListArray; // 数组里面放的是链表
46 private int size; // 表示共有多少条链表
47 //构造器
48 public HashTab(int size) { // size表示指定有多少条链表
49 this.size = size;
50 // 初始化empLinkedListArray
51 empLinkedListArray = new EmpLinkedList[size]; // 开辟空间
52 // 留一个坑 此时的链表数组能不能用?
53 // 这时不要忘了分别初始化每个链表
54 for (int i = 0; i < size ; i++) {
55 empLinkedListArray[i] = new EmpLinkedList();
56 }
57 }
58
59 // 添加雇员
60 public void add(Emp emp) { // 添加的时候给出一个雇员
61 // 根据员工的id,得到该员工应当添加到哪条链表
62 int empLinkedListNo = hashFun(emp.id);
63 // 将emp添加到对应链表
64 empLinkedListArray[empLinkedListNo].add(emp);
65 }
66
67 // 遍历所有的链表(哈希表)
68 public void list() {
69 for (int i = 0; i < size ; i++) {
70 empLinkedListArray[i].list(i);
71 }
72
73 }
74
75 // 编写一个散列函数,使用简单的取模法
76 public int hashFun(int id) {
77 return id % size;
78 }
79
80 }
81
82 // 表示雇员
83 class Emp {
84 public int id;
85 public String name;
86 public Emp next; // next 默认为空指向下一个雇员信息的指针
87
88 public Emp(int id, String name) { // 带参构造
89 super();
90 this.id = id;
91 = name;
92 }
93 }
94
95 // 创建EmpLinkedList ,表示链表
96 class EmpLinkedList {
97 // 头指针,执行第一个Emp,因此我们这个链表的head是有效的,直接指向第一个Emp
98 private Emp head; // 默认null
99
100 // 添加雇员到链表
101 // 说明
102 // 1)假定当添加雇员时,id自增长,即id的分配总是从小到大
103 // 因此我们将该雇员直接加入到本链表的最后即可
104 public void add(Emp emp) {
105 // 如果是添加第一个雇员
106 if (head == null) {
107 head = emp;
108 return;
109 }
110 // 如果不是添加第一个雇员,则使用一个辅助指针帮助定位到最后
111 Emp curEmp = head;
112 while(true) {
113 if (curEmp.next == null) { // 说明到链表最后
114 break;
115 }
116 curEmp = curEmp.next; // 后移
117 }
118 // 退出时直接将emp加入链表
119 curEmp.next = emp;
120 }
121
122 // 遍历链表的雇员信息
123 public void list(int no) {
124 if(head == null) { // 说明链表为空
125 System.out.println("第" + (no + 1) + "链表为空");
126 return;
127 }
128 System.out.print("第" + (no + 1) + "链表的信息为");
129 Emp curEmp = head; // 辅助指针
130 while(true) {
131 System.out.printf(" =>id= %d name = %s\t", , );
132 if(curEmp.next == null) { //说明curEmp是最后结点
133 break;
134 }
135 curEmp = curEmp.next; // 如果不是最后一个就后移
136 }
137 System.out.println();
138 }
139
140