加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 电商 > 正文

自己动手实现java数据结构(五)哈希表

发布时间:2021-04-04 12:21:30 所属栏目:电商 来源:网络整理
导读:1.哈希表介绍 前面我们已经介绍了许多类型的数据结构。在想要查询容器内特定元素时,有序向量使得我们能使用二分查找法进行精确的查询(( O(logN)对数复杂度,很高效 )。 可人类总是不知满足,依然在寻求一种更高效的特定元素查询的数据结构, 哈希表/散列表(

哈希表ADT接口:

自己动手实现java数据结构(五)哈希表

自己动手实现java数据结构(五)哈希表

  1 {
  2     /**
  3      * 存入键值对
  4      *  key   key值
  5  value value
  6  被覆盖的的value值
  7      */
  8     V put(K key,V value);
  9 
 10      11      * 移除键值对
 12  13  被删除的value的值
 14       15     V remove(K key);
 16 
 17      18      * 获取key对应的value值
 19  20       对应的value值
 21       22     V get(K key);
 23 
 24      25      * 是否包含当前key值
 26  27       true:包含 false:不包含
 28       29      containsKey(K key);
 30 
 31      32      * 是否包含当前value值
 33  value   value值
 34         true:包含 false:不包含
 35       36      containsValue(V value);
 37 
 38      39      * 获得当前map存储的键值对数量
 40  键值对数量
 41      *  42      size();
 43 
 44      45      * 当前map是否为空
 46   true:为空 false:不为空
 47       48      isEmpty();
 49 
 50      51      * 清空当前map
 52       53      clear();
 54 
 55      56      * 获得迭代器
 57  迭代器对象
 58       59     Iterator<EntryNode<K,1)"> iterator();
 60 
 61      62      * 键值对节点 内部类
 63  64      65          K key;
 66         V value;
 67         EntryNode<K,1)"> next;
 68 
 69         EntryNode(K key,V value) {
 70              key;
 71              value;
 72         }
 73 
 74          keyIsEquals(K key){
 75              key){
 76                 ;
 77             }
 78 
 79             ){
 80                 :::如果走到这步,this.key不等于null,不匹配
 81                  82             } 83                 .key);
 84  85  86 
 87         EntryNode<K,1)"> getNext() {
 88              89  90 
 91          next) {
 92              93  94 
 95          K getKey() {
 96              97  98 
 99          V getValue() {
100             101 102 
103          setValue(V value) {
104             105 106 
107         @Override
108          String toString() {
109             110 111     }
112 }
View Code

哈希表实现:

自己动手实现java数据结构(五)哈希表

自己动手实现java数据结构(五)哈希表

  2 
  3     ===========================================成员属性================================================
  4          * 内部数组
  7     [] elements;
  8 
  9      10      * 当前哈希表的大小
 12      size;
 13 
 14          * 负载因子
 16  loadFactor;
 18 
 19          * 默认的哈希表容量
 21  22          * 扩容翻倍的基数 两倍
 27      28 
 30      * 默认的负载因子
 31  32      33 
 34     ========================================构造方法===================================================
 35      36      * 默认构造方法
 37  38     @SuppressWarnings("unchecked")
 39      HashMap() {
 40          41          DEFAULT_LOAD_FACTOR;
 42         elements =  EntryNode[DEFAULT_CAPACITY];
 43  44 
 45          * 指定初始容量的构造方法
 47  capacity 指定的初始容量
 48  49     @SuppressWarnings("unchecked" capacity) {
 51          52          53         elements =  EntryNode[capacity];
 54  55 
 56          * 指定初始容量和负载因子的构造方法
 58  59  loadFactor 指定的负载因子
 60  61     @SuppressWarnings("unchecked" 62      loadFactor) {
 63          64          65         elements =  67 
 68     ==========================================内部辅助方法=============================================
 69      70      * 通过key的hashCode获得对应的内部数组下标
 71  key 传入的键值key
 对应的内部数组下标
 73  74      getIndex(K key){
 75         .elements);
 76  77 
 78      79      * 通过key的hashCode获得对应的内部数组插槽slot下标
 80  81  elements 内部数组
 82  83  84     [] elements){
 85          86             ::: null 默认存储在第0个桶内
 87              88         } 89              key.hashCode();
 91             :::通过 高位和低位的异或运算,获得最终的hash映射,减少碰撞的几率
);
 93              finalHashCode;
 94  95  96 
 97      98      * 获得目标节点的前一个节点
 99  currentNode 当前桶链表节点
100  key         对应的key
 返回当前桶链表中"匹配key的目标节点"的"前一个节点"
102      *          注意:当桶链表中不存在匹配节点时,返回桶链表的最后一个节点
103 104     105         :::不匹配
106         EntryNode<K,1)"> currentNode.next;
107         :::遍历当前桶后面的所有节点
:::如果下一个节点的key匹配
110             (nextNode.keyIsEquals(key)){
111                  currentNode;
112             }113                 :::不断指向下一个节点
114                 currentNode = nextNode;
115                 nextNode = nextNode.next;
116 117 118 
119         :::到达了桶链表的末尾,返回最后一个节点
120         121 122 
123     124      * 哈希表扩容
125 126     @SuppressWarnings("unchecked"127      reHash(){
128         :::扩容两倍
129         EntryNode<K,1)"> REHASH_BASE];
130 
131         :::遍历所有的插槽
132         ) {
133             134 135 136 
137         :::内部数组 ---> 扩容之后的新数组
138          newElements;
139 140 
141     142      * 单个插槽内的数据进行rehash
143 144     [] newElements){
145         :::获得当前插槽第一个元素
146         EntryNode<K,1)">.elements[index];
147         148             :::当前插槽为空,直接返回
149             150 151 
152         :::低位桶链表 头部节点、尾部节点
153         EntryNode<K,1)">154         EntryNode<K,1)">155         :::高位桶链表 头部节点、尾部节点
156         EntryNode<K,1)">157         EntryNode<K,1)">158 
159         160             :::获得当前节点 在新数组中映射的插槽下标
161             162             :::是否和当前插槽下标相等
163              index){
164                 :::和当前插槽下标相等
165                 166                     :::初始化低位链表
167                     lowListHead = currentEntryNode;
168                     lowListTail =169                 }170                     :::在低位链表尾部拓展新的节点
171                     lowListTail.next =172                     lowListTail = lowListTail.next;
173                 }
174             }175                 :::和当前插槽下标不相等
176                 177                     :::初始化高位链表
178                     highListHead =179                     highListTail =180                 }181                     :::在高位链表尾部拓展新的节点
182                     highListTail.next =183                     highListTail = highListTail.next;
184 185 186             :::指向当前插槽的下一个节点
187             currentEntryNode = currentEntryNode.next;
188 189 
190         :::新扩容elements(index)插槽 存放lowList
191         newElements[index] = lowListHead;
192         :::lowList末尾截断
193         194             lowListTail.next = 195 196 
197         :::新扩容elements(index + this.elements.length)插槽 存放highList
198         newElements[index +  highListHead;
199         :::highList末尾截断
200         201             highListTail.next = 202 203 204 
205     206      * 判断是否需要 扩容
207 208      needReHash(){
209         .loadFactor);
210 211 
212     ============================================外部接口================================================
213 
214     @Override
215     216         (needReHash()){
217             reHash();
218 219 
220         :::获得对应的内部数组下标
221          getIndex(key);
222         :::获得对应桶内的第一个节点
223         EntryNode<K,1)">224 
225         :::如果当前桶内不存在任何节点
226         227             :::创建一个新的节点
228             229             :::创建了新节点,size加1
230             231             232 233 
234         (firstEntryNode.keyIsEquals(key)){
235             :::当前第一个节点的key与之匹配
236             V oldValue = firstEntryNode.value;
237             firstEntryNode.value =238              oldValue;
239         }240             :::不匹配
241 
242             :::获得匹配的目标节点的前一个节点
243             EntryNode<K,key);
244             :::获得匹配的目标节点
245             EntryNode<K,1)"> targetPreviousNode.next;
246             247                 :::更新value的值
248                 V oldValue = targetNode.value;
249                 targetNode.value =250                 251             }252                 :::在桶链表的末尾 新增一个节点
253                 targetPreviousNode.next = 254                 255                 256                 257 258 259 260 
261 262      V remove(K key) {
263         264         265         266         EntryNode<K,1)">267 
268         269         270             271 272 
273         274             :::当前第一个节点的key与之匹配
275 
276             :::将桶链表的第一个节点指向后一个节点(兼容next为null的情况)
277              firstEntryNode.next;
278             :::移除了一个节点 size减一
279             280             :::返回之前的value值
281             282         }283             284 
285             286             EntryNode<K,1)">287             288             EntryNode<K,1)">289 
290             291                 :::将"前一个节点的next" 指向 "目标节点的next" ---> 相当于将目标节点从桶链表移除
292                 targetPreviousNode.next = targetNode.next;
293                 294                 295                 296             }297                 :::如果目标节点为空,说明key并不存在于哈希表中
298                 299 300 301 302 
303 304      V get(K key) {
305         306         307         308         EntryNode<K,1)">309 
310         311         312             313 314 
315         316             317             318         }319             320             EntryNode<K,1)">321             322             EntryNode<K,1)">323 
324             325                 326             }327                 328                 329 330 331 332 
333 334      containsKey(K key) {
335         V value = get(key);
336         337 338 
339 340      containsValue(V value) {
341         :::遍历全部桶链表
342         .elements) {
343             :::获得当前桶链表第一个节点
344             EntryNode<K,1)"> element;
345 
346             :::遍历当前桶链表
347             348                 :::如果value匹配
349                  (entryNode.value.equals(value)) {
350                     :::返回true
351                     352                 }  {
353                     :::不匹配,指向下一个节点
354                     entryNode = entryNode.next;
355 356 357 358 
359         :::所有的节点都遍历了,没有匹配的value
360         361 362 
363 364      size() {
365         .size;
366 367 
368 369      isEmpty() {
370         371 372 
373 374      clear() {
375         :::遍历内部数组,将所有桶链表全部清空
376         377             378 379 
380         :::size设置为0
381         382 383 
384 385      iterator() {
386          Itr();
387 388 
389 390     391         Iterator<EntryNode<K,1)">.iterator();
392 
393         :::空容器
394         iterator.hasNext()){
395             396 397 
398         :::容器起始使用"["
399         StringBuilder s = 400 
401         :::反复迭代
402         403             :::获得迭代的当前元素
404             EntryNode<K,1)"> iterator.next();
405 
406             :::判断当前元素是否是最后一个元素
407             408                 :::是最后一个元素,用"]"收尾
409                 s.append(data).append("]"410                 :::返回 拼接完毕的字符串
411                  s.toString();
412             }413                 :::不是最后一个元素
414                 
415                 s.append(data).append(",1)">416 417 418 419 
420     421      * 哈希表 迭代器实现
422      423     424         425          * 迭代器 当前节点
426          * 427         428 
429         430          * 迭代器 下一个节点
431 432         433 
434         435          * 迭代器 当前内部数组的下标
436 437          currentIndex;
438 
439         440          * 默认构造方法
441 442          Itr(){
443             :::如果当前哈希表为空,直接返回
444             .isEmpty()){
445                 446 447             :::在构造方法中,将迭代器下标移动到第一个有效的节点上
448 
449             :::遍历内部数组,找到第一个不为空的数组插槽slot
450             451                 :::设置当前index
452                  i;
453 
454                 EntryNode<K,1)">.elements[i];
455                 :::找到了第一个不为空的插槽slot
456                 457                     :::nextNode = 当前插槽第一个节点
458                      firstEntryNode;
459 
460                     :::构造方法立即结束
461                     462 463 464 465 
466 467          hasNext() {
468             469 470 
471 472          next() {
473             .nextNode;
474             :::暂存需要返回的节点
475             EntryNode<K,1)">476 
477             :::nextNode指向自己的next
478             .nextNode.next;
479             :::判断当前nextNode是否为null
480             481                 :::说明当前所在的桶链表已经遍历完毕
482 
483                 :::寻找下一个非空的插槽
484                 485                     486                     487 
488                     EntryNode<K,1)">489                     :::找到了后续不为空的插槽slot
490                     491                         492                         493                         :::跳出循环
494                         495                     }
496 497 498              needReturn;
499 500 
501 502          remove() {
503             504                 505 506 
507             :::获得需要被移除的节点的key
508             K currentKey = .currentNode.key;
509             :::将其从哈希表中移除
510             HashMap..remove(currentKey);
511 
512             :::currentNode设置为null,防止反复调用remove方法
513             514 515 516 }
View Code

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读