自己动手实现java数据结构(五)哈希表(5)
发布时间:2021-04-01 04:34 所属栏目:53 来源:网络整理
导读:哈希表ADT接口: 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 * 获
哈希表ADT接口: 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 哈希表实现: 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 (编辑:ASP站长网) |
相关内容
网友评论
推荐文章
热点阅读