哈希表的增删遍历
12. 哈希表(散列)
哈希表不是算法,是一种数据结构
问题导入:
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id, 性别,年龄,住址...),当输入该员工的id时,要求查找到该员工的所有信息
要求:不使用数据库,尽量节省内存,速度越开越好 => 哈希表(散列)
12.1 哈希表基本介绍:
散列表(Hash Table,也叫哈希表),是根据关键码值(key value)而直接进行访问的 **数据结构**。也就是说,它是通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做 **散列函数**。存放记录的 **数组** 叫做 **散列表**
1 package hashtable; 2 3 import java.util.Scanner; 4 5 public class HashTableDemo { 6 public static void main(String[] args) { 7 // 创建哈希表 8 HashTab hashTab = new HashTab(7); 9 10 // 写一个简单的菜单 11 String key = ""; 12 Scanner scanner = new Scanner(System.in); 13 while (true){ 14 System.out.println("add, 添加雇员"); 15 System.out.println("list,显示雇员"); 16 System.out.println("find,查找雇员"); 17 System.out.println("del, 删除雇员"); 18 System.out.println("exit, 退出系统"); 19 20 key = scanner.next(); 21 switch (key){ 22 case "add": 23 System.out.println("输入id"); 24 int id = scanner.nextInt(); 25 System.out.println("输入名字:"); 26 String name = scanner.next(); 27 // 创建雇员 28 Emp emp = new Emp(id,name); 29 hashTab.add(emp); 30 break; 31 case "list": 32 hashTab.list(); 33 break; 34 case "find": 35 System.out.println("请输入要查找id"); 36 id = scanner.nextInt(); 37 hashTab.findEmpById(id); 38 break; 39 case "del": 40 System.out.println("请输入要查找id"); 41 id = scanner.nextInt(); 42 hashTab.delEmpById(id); 43 break; 44 case "exit": 45 scanner.close(); 46 break; 47 48 } 49 } 50 } 51 } 52 53 // 创建HashTable 管理多条链表 54 class HashTab{ 55 private EmpLinkedList[] empLinkedListArray; 56 private int size; // 表示右多少条链表 57 // 构造器 58 public HashTab(int size){ 59 this.size = size; 60 // 初始化empLinkedListArray 61 empLinkedListArray = new EmpLinkedList[size]; 62 // 这是不要忘了初始化,我们的new一个链表 63 for (int i = 0; i < size; i++){ 64 empLinkedListArray[i] = new EmpLinkedList(); 65 } 66 } 67 68 // 添加雇员 69 public void add(Emp emp){ 70 // 根据员工的id得到该员工应该加入到哪条链表 71 int empLinkedListNO = hashFun(emp.id); 72 // 将emp 添加到对应的链表中 73 empLinkedListArray[empLinkedListNO].add(emp); 74 } 75 76 // 根据输入的id查找雇员 77 public void findEmpById(int id){ 78 int empLinkedListNo = hashFun(id); 79 Emp emp = empLinkedListArray[empLinkedListNo].findEmpById(id); 80 if (emp != null){ 81 System.out.printf("在第%d条表中找到雇员id = %d\n",empLinkedListNo + 1, id); 82 }else { 83 System.out.println("Find null"); 84 } 85 } 86 // 根据输入的id查找雇员 87 public void delEmpById(int id){ 88 int empLinkedListNo = hashFun(id); 89 boolean flag = empLinkedListArray[empLinkedListNo].delEmpById(id); 90 if (flag){ 91 System.out.println("success"); 92 }else{ 93 System.out.println("false"); 94 } 95 } 96 // 遍历所有的链表, 遍历hashtab 97 public void list(){ 98 for (int i = 0; i < size; i++){ 99 empLinkedListArray[i].list(i); 100 } 101 } 102 // 编写一个散列函数,使用一个简单的取模法 103 public int hashFun(int id){ 104 return id % size; 105 } 106 } 107 108 109 // 表示一个雇员 110 class Emp{ 111 public int id; 112 public String name; 113 public Emp next; // next默认为空 114 115 public Emp(int id, String name) { 116 super(); 117 this.id = id; 118 this.name = name; 119 } 120 } 121 // 创建一个EmpLikList, 表示链表 122 class EmpLinkedList{ 123 // 头指针,执行第一个Emp,因此我们呢这个链表的head,是直接指向第一个Emp 124 private Emp head; // 默认为 null 125 126 // 添加雇员到链表 127 // 说明 128 // 1. 假定,当添加雇员时,id是自增的,即id的分配总是从小到大 129 // 因此我们将该雇员直接加入到本链表的最后即可 130 public void add(Emp emp) { 131 // 如果是添加第一个雇员 132 if (head == null){ 133 head = emp; 134 return; 135 } 136 // 如果不是第一个雇员,则使用一个辅助的指针,帮助定位到最后 137 Emp curEmp = head; 138 while (true){ 139 if (curEmp.next == null){ 140 break; 141 } 142 curEmp = curEmp.next; // 后移,直到最后 143 } 144 // 退出时直接将emp 加入链表 145 curEmp.next = emp; 146 } 147 148 // 遍历链表的雇员信息 149 public void list(int no){ 150 if (head == null){ 151 System.out.println(no+1 + "Empty List"); 152 return; 153 } 154 System.out.println(no+1 + "message:"); 155 Emp curEmp = head; // 辅助指针 156 while(true){ 157 System.out.printf("id=%d name=%s\t",curEmp.id,curEmp.name); 158 if (curEmp.next == null){ 159 // 说明curEmp已经为空了 160 break; 161 } 162 curEmp = curEmp.next; 163 } 164 } 165 166 // 根据id删除雇员 167 // 如果查找到就返回Emp,如果没有,就返回null 168 public Emp findEmpById(int id){ 169 // 判断链表是否为空 170 if (head == null){ 171 System.out.println("链表为空"); 172 return null; 173 } 174 // 辅助指针 175 Emp curEmp = head; 176 while (true){ 177 if(curEmp.id == id){ 178 // 这时curEmp就指向要查找的雇员说明找到了 179 break; 180 } 181 // 退出 182 if (curEmp.next == null){ 183 // 说明遍历该链表没有找到 184 curEmp = null; 185 break; 186 } 187 curEmp = curEmp.next; 188 } 189 return curEmp; 190 } 191 192 // 根据id查找雇员 193 // 如果查找到就返回Emp,如果没有,就返回null 194 public boolean delEmpById(int id){ 195 // 判断链表是否为空 196 if (head == null){ 197 System.out.println("链表为空"); 198 return false; 199 } 200 // 辅助指针 201 Emp curEmp = head; 202 while (true){ 203 if(curEmp.id == id){ 204 // 这时curEmp就指向要查找的雇员说明找到了 205 break; 206 } 207 // 退出 208 if (curEmp.next == null){ 209 // 说明遍历该链表没有找到 210 curEmp = null; 211 break; 212 } 213 curEmp = curEmp.next; 214 } 215 if (curEmp != null) { 216 head = null; 217 return true; 218 }else { 219 System.out.println("NULL "); 220 return false; 221 } 222 } 223 224 225 }

浙公网安备 33010602011771号