哈希表的增删遍历


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 }

 

posted @ 2021-08-06 21:43  笔锋  阅读(137)  评论(0)    收藏  举报