`
不平凡的人
  • 浏览: 35242 次
  • 性别: Icon_minigender_1
  • 来自: 嘉峪关
社区版块
存档分类
最新评论

HashMap介绍

阅读更多

 1.哈希表:

 

(1)说哈希表之前不得说一下算法,我们都知道评价一个好的算法主要要从时间空间复杂度来进行衡量。

时间复杂度就是执行算法所需要的时间,而空间付再度就是该算法所占的内存空间。两者均体现了计算机的资源的概念。毋庸置疑,对于一个数组我们都清楚,查找一个元素只要知道索引位置就可以了,因此,时间复杂度为O(1),然而对于一个链表其时间复杂度为O(n)。

 

(2)理想的情况就是不需要比较一次就能得到所查的记录,换言之,在记录的存储位置与他的关键字k之间建立一个确定的对应关系f,使得每一个关键字和结构中的一个位置唯一的对应,即f(k)。此时,称f为哈希函数。用该函数建的表为哈希表。

 

(3)几个基本概念:

冲突:不同关键字得到相同而的哈希值。

 

散列:散列函数:将数据的hashCode映射到表中的位置,这一映射过程叫做哈希造表或散列,此过程不需给出冲突解决方案。

 

好的散列函数的2个必备条件:1,快捷,在O(1)时间内运行;2,均匀的分布hashCode,填充概率相同。

 

哈希地址:根据关键字所得到的记录的存储位置。

 

冲突解决方案:当一个新项散列到已经被占据的散列表中的位置时,被告之发生冲突,解决方案用于确定新项可以插入散列表中未被占据的位置。

    解决冲突主要的主要方法:开放寻址方法(寻找另外的空位);封闭寻址方法(吊挂另一种数据结构)

一般采用后者挂链表的方式。

 

再散列:当数据的容量大于散列表的容量的容量时,那么创建一张指定新容量的表,再将原来表中的数据映射到新表中。

 

2.关于HashMap的简单介绍:

 

HashMap 的实例有两个参数影响其性能:初始容量加载因子容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

 

3.HashMap存储

HashMap<String ,int> hp = new HashMap<String,int>();

hp.put(“张三",20);

hp.put("李四",21);

 

4.HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置。
当程序执行 hp.put("张三" , 20); 时,系统将调用"张三"的 hashCode() 方法得到其 hashCode 值。每个对象都有 hashCode() 方法,都可通过该方法获得它的 hashCode 值。得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置。

 

 

参考put();方法的源码:

 

 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value 即可.

 

public V put(K key, V value){
   
// 如果 key 为 null,调用 putForNullKey 方法进行处理  
 if (key == null)   
    return putForNullKey(value);
  
//每个key.hashCode()返回一个hash值  
int hash = hash(key.hashCode());
  
// 根据key.hashCode()的值来找记录的位置  
  int i = indexFor(hash, table.length);
 
// 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素  
 for (Entry<K,V> e = table[i]; e != null; e = e.next)   
 {   
     Object k;
   
     // 找到指定 key 与需要将要存入的 key 相等 ,将   
     if (e.hash == hash && ((k = e.key) == key   
         || key.equals(k)))   
     {   
         V oldValue = e.value;   
         e.value = value;   
         e.recordAccess(this);   
         return oldValue;   
     }   
 }   
 // 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry   
 modCount++;   
 // 将 key、value 添加到 i 索引处  
 addEntry(hash, key, value, i);   
 return null;
}   
  (1)  Entry就是HashMap存储数据所用的类,相当于链表的节点;每个 Map.Entry 其实就是一个 key-value 对;我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。


(2)&按位取并的操作符,前提是length为2的n次幂。

 

public  void addEntry(int hash, K key, V value, int bucketIndex){
  
    // 获取指定 bucketIndex 索引处的 Entry   
    Entry<K,V> e = table[bucketIndex];
 
    // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry   
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
   
    // 如果 Map 中的 key-value 对的数量超过了极限
if (size++ >= threshold) 

  
        //  table 对象的长度扩充到 2 倍。  
        resize(2 * table.length);


}


系统总是将新添加的 Entry 对象放入 table 数组的 bucketIndex 索引处,如果 bucketIndex 索引处已经有了一个 Entry 对象,那新添加的 Entry 对象指向原有的 Entry 对象(产生一个 Entry 链)。

 

当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value。

 

参考一下get()方法的源码:

public V get(Object key){
   
// 如果 key 是 null,调用 getForNullKey 取出对应的 value   
if (key == null)   
     return getForNullKey();
   
 // 根据该 key 的 hashCode 值计算它的 hash 码  
 int hash = hash(key.hashCode());
  
 // 直接取出 table 数组中指定索引处的值,  
 for (Entry<K,V> e = table[indexFor(hash, table.length)];   
     e != null;   
     // 搜索该 Entry 链的下一个 Entr   
     e = e.next)           
 {   
     Object k;
   
     // 如果该 Entry 的 key 与被搜索 key 相同
      if (e.hash == hash && ((k = e.key) == key   
         || key.equals(k)))   
         return e.value;   
 }   
 return null;

 

 (1)HashMap 的每个 bucket 里只有一个 Entry 时,HashMap 可以根据索引、快速地取出该 bucket 里的 Entry;在发生“Hash 冲突”的情况下,单个 bucket 里存储的不是一个 Entry,而是一个 Entry 链,系统只能必须按顺序遍历每个 Entry,直到找到想搜索的 Entry 为止,如果恰好要搜索的 Entry 位于该 Entry 链的最末端(该 Entry 是最早放入该 bucket 中),那系统必须循环到最后才能找到该元素。

 

(2)如果 HashMap 中 Entry 的数量一直不会超过极限容量(capacity * load factor),HashMap 就无需调用 resize() 方法重新分配 table 数组,从而保证较好的性能。当然,开始就将初始容量设置太高可能会浪费空间(系统需要创建一个长度为 capacity 的 Entry 数组)。
 

分享到:
评论

相关推荐

    HashMap介绍和使用

    ### HashMap介绍和使用详解 #### 一、HashMap的数据结构 HashMap是Java集合框架的一个重要组成部分,它实现了Map接口,能够存储键值对映射。在Java编程语言中,最基本的数据结构有两种:数组和引用(模拟指针)。...

    51. ArrayList LinkedList Set HashMap介绍.txt

    #### 实现类介绍 - **HashSet**:基于哈希表实现,提供高效的元素插入、删除和查找操作。元素无序,不能保证元素的顺序。 - **TreeSet**:基于红黑树实现,能够对元素进行排序,支持高效的范围查询。元素按自然顺序...

    关于如何解决HashMap线程安全问题的介绍

    在Java编程中,HashMap是一个非常常用的集合类,用于存储键值对数据。然而,它存在一个重要的特性,那就是线程不安全。理解这个问题并找到解决方案是每个Java开发者必须掌握的知识。 HashMap线程不安全的原因主要...

    treemap treeset hashset hashmap 简要介绍

    这些集合类各自有着独特的特性和应用场景,下面将对它们进行详细介绍。 ### TreeMap `TreeMap`是基于红黑树(Red-Black tree)实现的Sorted Map(排序映射)。它实现了`Map`接口,并且提供了一些额外的方法,如`...

    Java HashMap类详解

    本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,虽然...

    HASHMAP排序功能描述

    本文将详细介绍如何对HashMap进行排序以及相关的知识点。 **1. HashMap的特点** HashMap的核心特点是其内部通过哈希函数来计算元素的存储位置,这使得查找、插入和删除操作的时间复杂度在平均情况下为O(1)。然而,...

    HashMap与HashTable区别

    下面将详细介绍`HashMap`和`HashTable`之间的区别。 #### 一、线程安全性 - **HashTable**: 是线程安全的。它通过内部同步(synchronized)机制确保了多线程环境下的安全性。这意味着在多线程环境中,对`HashTable...

    HASHMAP缓存.txt

    综上所述,《HASHMAP缓存.txt》文档不仅介绍了HashMap作为缓存的基本概念和实现方式,还涉及到了单例模式、线程安全、性能优化等高级主题,为开发者提供了丰富的技术细节和实用建议。在实际开发中,合理运用这些知识...

    hashmap与hashtable区别

    然而,在实际应用过程中,这两种数据结构有着本质的不同,下面将详细介绍这些差异。 #### 1. 历史背景及实现原理 - **Hashtable**:该类继承自`Dictionary`类,并且实现了`Map`接口。它最早出现在Java 1.0版本中,...

    hashMap工具类

    在本篇文章中,我们将详细介绍一个名为`hashMap`的工具类,该类被设计用于Adobe Flex应用程序中,旨在提供一种简单且高效的方法来处理键值对数据结构。通过深入分析该类的实现细节,我们能够更好地理解其内部机制,...

    asp hashmap,arraylist实现

    通常,这样的博客可能会介绍如何在ASP.NET代码中创建和使用HashMap和ArrayList,包括如何添加、删除和查找元素,以及它们在实际应用场景中的差异和选择原则。 标签中的“源码”意味着文章可能包含实际的代码示例,...

    HashMap底层原理.pdf

    本文将详细介绍HashMap的底层原理,包括其内部实现结构、关键字段的作用、以及JDK 1.7和JDK 1.8版本的主要区别。 首先,HashMap是基于哈希表的Map接口非同步实现,它允许使用null值和null键,这意味着HashMap在设计...

    ibatis 用HashMap解决resultClass映射

    本文将详细介绍如何利用 ibatis 框架通过 `HashMap` 来解决这一问题。 #### 1. 什么是 ibatis? ibatis 是一个基于 Java 的开源持久层框架,它提供了 SQL 映射功能,使得开发者可以通过 XML 文件或注解来定义 SQL ...

    java 使用web service读取HashMap里的数值

    本文将详细介绍如何在Java WebService中使用`HashMap`来传递和读取数据。 #### WebService与HashMap的基本概念 1. **WebService**:一种开放的标准服务,通过HTTP协议进行数据传输,可以跨平台、跨语言地提供服务...

    hashMap工作原理

    详细介绍了hashMap原理,值得一看,对于面试者有很大帮助

    hashmap.zip

    - "讲义"可能系统地介绍了HashMap的基础知识,如插入、查找和删除的步骤,以及HashMap与其他数据结构(如TreeMap)的区别。 通过深入研究这些资源,开发者可以更好地掌握HashMap的使用技巧,避免常见的性能问题,并...

    Hashmap 通过对VALUE排序 源代码

    在博文“HashMap通过对VALUE排序 源代码”中,作者可能详细介绍了如何实现上述方法,尤其是自定义Comparator来对HashMap的值进行排序。遗憾的是,由于没有提供具体的博客内容,我们无法给出更详细的源代码分析。不过...

    Java基础-模拟HashMap集合(基于数组和链表) 数组和链表.pdf

    在本文中,我们将详细介绍如何模拟Java的HashMap集合,使用数组和链表来实现Hash表的存储。我们将从基本概念开始,逐步深入到HashMap的实现细节中。 什么是HashMap? HashMap是一种基于散列表的数据结构,用于存储...

    jdom 解析xml存入hashmap的例子

    本篇将详细介绍如何使用JDOM解析XML文件,并将其内容存入HashMap中。 首先,我们需要了解JDOM的基本使用。JDOM的核心类包括`SAXBuilder`用于解析XML文档,`Document`表示整个XML文档,`Element`代表XML的元素节点,...

    HashMap模块源码—— 高效随机存取数据结构 ,文本索引必备

    资源介绍:。1、此HashMap类采用java jdk中HashMap的实现方式。2、相比网站上发布过的hashtable之类的源码:。此HashMap寻址方法是拉链法.比开放寻址法对连续内存要求更低。哈希函数用的是java中String.hashCode()...

Global site tag (gtag.js) - Google Analytics