• 【Java集合学习】HashMap源码之“拉链法”散列冲突的解决


    1.HashMap的概念

    HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

    HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
    HashMap 的实现不是同步的,这意味着它是线程不安全的。它的key、value都可以为null。此外,HashMap中的映射是无序的。

      本文重点是介绍HashMap中的“拉链法”解决散列冲突。如果想了解其他方面的知识可参考http://www.cnblogs.com/skywang12345/p/3310835.html。

    下面先介绍一下散列表及散列冲突的基本概念。

    2.Hash表的概念

      我们知道,有一种数据结构能够快速地查找所需的对象(O(1)时间复杂度),这就是散列表(hash table)。散列码(hash code)是由对象的实例产生的一个整数。

    更准确的说,具有不同的数据域的对象将产生不同的散列码。如下图(这里顺带提一下散列表的概念,即哈希表的概念):

      设所有可能出现的关键字集合记为U(简称全集)。实际发生(即实际存储)的关键字集合记为K(|K|比|U|小得多)。
         散列方法是使用函数h将U映射到表T[0..m-1]的下标上(m=O(|U|))。这样以U中关键字为自变量,以h为函数的运算结果就是相应结点的存储地址。从而达到在O(1)时间内就可完成查找。
        其中:
         ① h:U→{0,1,2,…,m-1} ,通常称h为散列函数(Hash Function)。散列函数h的作用是压缩待处理的下标范围,使待处理的|U|个值减少到m个值,从而降低空间开销。
         ② T为散列表(Hash Table)。
         ③ h(Ki)(Ki∈U)是关键字为Ki结点存储地址(亦称散列值或散列地址)。
         ④ 将结点按其关键字的散列地址存储到散列表中的过程称为散列(Hashing)

    3.散列冲突

      两个不同的关键字,由于散列函数值相同,因而被映射到同一表位置上。该现象称为冲突(Collision)或碰撞。发生冲突的两个关键字称为该散列函数的同义词(Synonym)。

    上图中的k2≠k5,但h(k2)=h(k5),故k2和K5所在的结点的存储地址相同。

    有了冲突,那自然要尽可能地去避免冲突。那么如何安全避免冲突呢?有两个条件:

    1. 其一是|U|≤m;
    2. 另一个是设计合适的哈希函数。

       这只适用于|U|较小,且关键字均事先已知的情况,此时经过精心设计散列函数h有可能完全避免冲突。通常情况下,h是一个压缩映像。虽然|K|≤m(已知的关键字),但|U|>m(未知的关键字),故无论怎样设计h,也不可能完全避免冲突。因此,只能在设计h时尽可能使冲突最少。同时还需要确定解决冲突的方法,使发生冲突的同义词能够存储到表中。

      HashMap中采用的“拉链法”就是一种冲突解决的方式(hash函数的设计才是冲突避免,但不是一种完全的冲突解决方法),如下图所示为“拉链法”结构。

      但是HashMap中的节点是Map.Entry类型的,而不是简单的value,如下图所示,左边是一个Node<K,V>[] table数组(在jdk6中是Entry<K,V>数组),Node是Map.Entry的实现类。

      那么它是如何解决冲突的呢?即key值不同的两个或多个Map.Entry<K,V>可能会插在同一个桶下面,但是当查找到某个特定的hash值的时候,下面挂了很多个<K,V>映射,怎么确定哪个是我要找的那个<K,V>呢?这就是HashMap底层结构的一个亮点,在它的Entry中不仅仅只是插入value的,他是插入整个Entry 的,里面包含key和value的,所以能识别同一个hash值下的不同Map.Entry,想要了解更多,建议查看源码。

  • 相关阅读:
    c++ socket发送数据时,sendData = char * string 导致的乱码问题
    c++ sprintf() 用法
    c++ 将float 类型转换成string 类型
    c++中 string类型 转为 char []类型
    c++ 去掉所有空格及换行符
    c++处理字符串string.find()与string::npos
    C1010 unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source
    C++ socket bind() 函数绑定错误
    windows 全局安装 composer
    VMware Tools (ubuntu系统)安装详细过程与使用
  • 原文地址:https://www.cnblogs.com/chohyee/p/7404209.html
Copyright © 2020-2023  润新知