25、哈希表
来源:https://www.bilibili.com/video/BV1B4411H76f?p=77
一、问题/需求
希望在不使用数据库的情况下,存储一个公司的雇员信息(id,姓名等),尽量节省内存,速度越快越好。这时候可以用哈希表。
哈希表:也叫散列表,通过key-value的形式对数据进行访问,可以加快查找速度。具体来说,它的结构是数组+链表(或数组+二叉树)的形式。把关键码值(例如员工ID)映射到数组中,对数组下对应的链表进行存储或访问。这样的映射函数也叫散列函数。(常用的映射方式:关键码值对数组大小取余)
哈希表可以用作简单的java程序与SQL之间的缓存。
二、实现一个哈希表,存储雇员信息
1 public class HashTable { 2 public static void main(String[] args) { 3 HashTab hashTab = new HashTab(7); 4 5 String key = ""; 6 Scanner scanner = new Scanner(System.in); 7 while (true){ 8 System.out.println(); 9 System.out.println("add:添加雇员"); 10 System.out.println("show:显示雇员"); 11 System.out.println("select:查找雇员"); 12 System.out.println("exit:退出系统"); 13 14 key = scanner.next(); 15 switch (key){ 16 case "add": 17 System.out.println("输入ID"); 18 int id = scanner.nextInt(); 19 System.out.println("输入name"); 20 String name = scanner.next(); 21 Emp emp = new Emp(id, name); 22 hashTab.add(emp); 23 break; 24 case "show": 25 hashTab.show(); 26 break; 27 case "select": 28 System.out.println("输入ID"); 29 id = scanner.nextInt(); 30 hashTab.selecyById(id); 31 break; 32 case "exit": 33 scanner.close(); 34 System.exit(0); 35 default: 36 break; 37 } 38 } 39 } 40 } 41 42 //哈希表 43 class HashTab{ 44 //创建一个数组,数组内容的类型为下面的链表 45 private EmpLinkedList[] empLinkedLists; 46 private int size; 47 48 public HashTab(int size) { 49 this.size = size; 50 empLinkedLists = new EmpLinkedList[size]; 51 for (int i = 0; i < size; i++) { 52 empLinkedLists[i] = new EmpLinkedList(); 53 } 54 } 55 56 //散列函数(映射方法) 57 public int hashFunction(int id){ 58 return id % size; 59 } 60 61 //添加雇员 62 public void add(Emp emp){ 63 int hashNo = hashFunction(emp.id); 64 empLinkedLists[hashNo].add(emp); 65 } 66 67 //展示所有雇员 68 public void show(){ 69 for (int i = 0; i < size; i++) { 70 empLinkedLists[i].show(i); 71 } 72 } 73 74 //查找雇员 75 public void selecyById(int id){ 76 int hashNo = hashFunction(id); 77 Emp emp = empLinkedLists[hashNo].selectById(id); 78 if(emp == null){ 79 System.out.println("没有找到雇员"); 80 }else { 81 System.out.printf("在第%d条链表中找到了雇员,id = %d",hashNo+1,id); 82 System.out.println(); 83 } 84 } 85 } 86 87 //可以存放雇员的链表 88 class EmpLinkedList{ 89 private Emp head = null; 90 91 //增加雇员 92 public void add(Emp emp){ 93 if(head == null){ 94 head = emp; 95 return; 96 } 97 Emp curEmp = head; 98 while (true){ 99 if(curEmp.next == null){ 100 break; 101 } 102 curEmp = curEmp.next; 103 } 104 curEmp.next = emp; 105 } 106 107 //展示链表下的所有雇员 no:关键码值映射出来的数组内容 108 public void show(int no){ 109 if(head == null){ 110 System.out.println("第"+no+"条链表为空"); 111 return; 112 } 113 System.out.println("第"+no+"条链表的内容为:"); 114 Emp curEmp = head; 115 while (true){ 116 System.out.print("id="+curEmp.id+",name="+curEmp.name); 117 if(curEmp.next == null){ 118 break; 119 } 120 curEmp = curEmp.next; 121 } 122 System.out.println(); 123 } 124 125 //通过id查找雇员信息 126 public Emp selectById(int id){ 127 if (head == null){ 128 System.out.println("链表为空"); 129 return null; 130 } 131 Emp curEmp = head; 132 while (true){ 133 if(curEmp.id == id){ 134 break; 135 } 136 if(curEmp.next == null){ 137 curEmp = null; 138 break; 139 } 140 curEmp = curEmp.next; 141 } 142 return curEmp; 143 } 144 } 145 146 147 //雇员类 148 class Emp{ 149 public int id; 150 public String name; 151 public Emp next; 152 153 public Emp(int id, String name) { 154 this.id = id; 155 this.name = name; 156 } 157 }
测试及结果
add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统 show 第0条链表为空 第1条链表为空 第2条链表为空 第3条链表为空 第4条链表为空 第5条链表为空 第6条链表为空 add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统 add 输入ID 5 输入name aa add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统 add 输入ID 6 输入name bb add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统 add 输入ID 7 输入name cc add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统 show 第0条链表的内容为: id=7,name=cc 第1条链表为空 第2条链表为空 第3条链表为空 第4条链表为空 第5条链表的内容为: id=5,name=aa 第6条链表的内容为: id=6,name=bb add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统 select 输入ID 7 在第1条链表中找到了雇员,id = 7 add:添加雇员 show:显示雇员 select:查找雇员 exit:退出系统