zoukankan      html  css  js  c++  java
  • JDK之Hash原理与算法

    思考一下如何取得这几个数

     显然,用0,1判断是最快的 没有值都是0,只有有值得才是1,要【判断是否这个数在这个数组里面就直接用if(50)=1即可知道了,够简单吧】,在这100个New 出来的数组空间中,显然这种方式不需要什么二分也不需要快速查找了,

    但是有一个很重要缺点就是如果是一亿大小的话,这根本不可能New 一亿出来,不过这就是最简单原始的hash即散列表,就是在数组的基础上的散列。

    而同样在散列表的基础上的函数就是散列函数(即)-------------------------------hash函数

    让我们再来思考思考

     刚刚的假设用到这里来,真的就一亿大小数组,怎样判断!

    思考一办法1:取余

     不能用0 1页很简单就是重复会很多。】、

    所以还是要10

     但是看下面这种方法还是有问题

     a[0]冲突了即-----------------哈希冲突,

    怎么办?所以这个方法不行!

    不过讲到哈希冲突了那就可以了解一下它,会发现踏实不可避免的,而且经常用的java的md5就也是理论上的会哈希冲突

    看图

     那么肯定有问题就会有解决方案

    方案一(不是重点).开放寻址

     

    这样查找也很简单 ,比如要找20,从绿色的开始找,发现a[0]不仅是绿色的也是模之后值为0即a[0]=0,但是发现不是要的20所以下一位绿色,就这样找到a[2]

    但是这样又有问题了那就是删除了数据怎么办,比如1没了即a[1]这时a[2]的20按照逻辑应该在a[1]去,才符合开放寻址的逻辑,这时候怎么办,Hash不能移!

    看图

     引进一个delete即删除了都会有delete标签,就像这个绿色标签一样,查找的时候所以就是查找delete,和绿色 两项不只是绿色。

    方法二:链表(重点)

     这时候的a[]就不存数据,而是key。如%10=0的即模10为0的都在 0这里找。链表的好处,详情参考数据结构链表 ,增加和插入删除等,很容易。不过!  ------遍历比较慢。

    这时就引进树

     而为了不让查询时树也变成链表。所以引进红黑树,颜色,左右旋等操作。

    那么我们的hashmap就是这样一个结构表+红黑树

    首先得知道hashmap是有两个版本的jdk 1.7和1.8。而大于8的时候就引进了红黑树,7之前都是链表,为什么呢 因为Jdk经过测试,hashmap因为左右旋等操作会有消耗

    在1.7里面反而更慢。在1.8才更快、看图

      那么接来下开始hashmap的常见操作

    ashMap共有4个构造函数,如下:

    复制代码
    // 默认构造函数。
    HashMap()
    
    // 指定“容量大小”的构造函数
    HashMap(int capacity)
    
    // 指定“容量大小”和“加载因子”的构造函数
    HashMap(int capacity, float loadFactor)
    
    // 包含“子Map”的构造函数
    HashMap(Map<? extends K, ? extends V> map)
    复制代码

    HashMap的API

    复制代码
    void                 clear() //clear() 的作用是清空HashMap。它是通过将所有的元素设为null来实现的。
    Object               clone() //clone()方法的作用很简单,就是克隆一个HashMap对象并返回。
    boolean              containsKey(Object key) //containsKey() 的作用是判断HashMap是否包含key返回“键为key”的键值对
    boolean              containsValue(Object value) //containsValue() 的作用是判断HashMap是否包含“值为value”的元素。第一,若“value为null”,则调用containsNullValue()。第二,若“value不为null”,则查找HashMap中是否有值为value的节点。
    Set<Entry<K, V>>     entrySet() //entrySet()的作用是返回“HashMap中所有Entry的集合”,它是一个集合。我们通过entrySet()获取到的Iterator的next()方法去遍历HashMap时,实际上调用的是 nextEntry() 。而nextEntry()的实现方式,先遍历Entry(根据Entry在table中的序号,从小到大的遍历);然后对每个Entry(即每个单向链表),逐个遍历。
    V                    get(Object key) //get() 的作用是获取key对应的value
    boolean              isEmpty() //判断是否为0
    Set<K>               keySet() //设置key
    V                    put(K key, V value) //put() 的作用是对外提供接口,让HashMap对象可以通过put()将“key-value”添加到HashMap中。
    void                 putAll(Map<? extends K, ? extends V> map) //putAll() 的作用是将"map"的全部元素都添加到HashMap中
    V                    remove(Object key) //remove() 的作用是删除“键为key”元素
    int                  size() //
    Collection<V>        values()
    复制代码

     从图中可以看出: 
    (01) HashMap继承于AbstractMap类,实现了Map接口。Map是"key-value键值对"接口,AbstractMap实现了"键值对"的通用函数接口。 
    (02) HashMap是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, size, threshold, loadFactor, modCount。
      table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。 
      size是HashMap的大小,它是HashMap保存的键值对的数量。 
      threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。threshold的值="容量*加载因子",当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。
      loadFactor就是加载因子。 
      modCount是用来实现fail-fast机制的。

    HashMap遍历方式

    4.1 遍历HashMap的键值对

    第一步:根据entrySet()获取HashMap的“键值对”的Set集合。
    第二步:通过Iterator迭代器遍历“第一步”得到的集合。

    复制代码
    // 假设map是HashMap对象
    // map中的key是String类型,value是Integer类型
    Integer integ = null;
    Iterator iter = map.entrySet().iterator();
    while(iter.hasNext()) {
        Map.Entry entry = (Map.Entry)iter.next();
        // 获取key
        key = (String)entry.getKey();
            // 获取value
        integ = (Integer)entry.getValue();
    }
    复制代码

    4.2 遍历HashMap的键

    第一步:根据keySet()获取HashMap的“键”的Set集合。
    第二步:通过Iterator迭代器遍历“第一步”得到的集合。

    复制代码
    // 假设map是HashMap对象
    // map中的key是String类型,value是Integer类型
    String key = null;
    Integer integ = null;
    Iterator iter = map.keySet().iterator();
    while (iter.hasNext()) {
            // 获取key
        key = (String)iter.next();
            // 根据key,获取value
        integ = (Integer)map.get(key);
    }
    复制代码

    4.3 遍历HashMap的值

    第一步:根据value()获取HashMap的“值”的集合。
    第二步:通过Iterator迭代器遍历“第一步”得到的集合。

    复制代码
    // 假设map是HashMap对象
    // map中的key是String类型,value是Integer类型
    Integer value = null;
    Collection c = map.values();
    Iterator iter= c.iterator();
    while (iter.hasNext()) {
        value = (Integer)iter.next();
    }

    下面通过一个实例学习如何使用HashMap

    import java.util.Map;
    import java.util.Random;
    import java.util.Iterator;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map.Entry;
    import java.util.Collection;

    /*
    * @desc HashMap测试程序
    *
    * @author skywang
    */
    public class HashMapTest {

    public static void main(String[] args) {
    testHashMapAPIs();
    }

    private static void testHashMapAPIs() {
    // 初始化随机种子
    Random r = new Random();
    // 新建HashMap
    HashMap map = new HashMap();
    // 添加操作
    map.put("one", r.nextInt(10));
    map.put("two", r.nextInt(10));
    map.put("three", r.nextInt(10));

    // 打印出map
    System.out.println("map:"+map );

    // 通过Iterator遍历key-value
    Iterator iter = map.entrySet().iterator();
    while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
    }

    // HashMap的键值对个数
    System.out.println("size:"+map.size());

    // containsKey(Object key) :是否包含键key
    System.out.println("contains key two : "+map.containsKey("two"));
    System.out.println("contains key five : "+map.containsKey("five"));

    // containsValue(Object value) :是否包含值value
    System.out.println("contains value 0 : "+map.containsValue(new Integer(0)));

    // remove(Object key) : 删除键key对应的键值对
    map.remove("three");

    System.out.println("map:"+map );

    // clear() : 清空HashMap
    map.clear();

    // isEmpty() : HashMap是否为空
    System.out.println((map.isEmpty()?"map is empty":"map is not empty") );
    }
    }


    复制代码
     1 import java.util.Map;
     2 import java.util.Random;
     3 import java.util.Iterator;
     4 import java.util.HashMap;
     5 import java.util.HashSet;
     6 import java.util.Map.Entry;
     7 import java.util.Collection;
     8 
     9 /*
    10  * @desc HashMap测试程序
    11  *        
    12  * @author skywang
    13  */
    14 public class HashMapTest {
    15 
    16     public static void main(String[] args) {
    17         testHashMapAPIs();
    18     }
    19     
    20     private static void testHashMapAPIs() {
    21         // 初始化随机种子
    22         Random r = new Random();
    23         // 新建HashMap
    24         HashMap map = new HashMap();
    25         // 添加操作
    26         map.put("one", r.nextInt(10));
    27         map.put("two", r.nextInt(10));
    28         map.put("three", r.nextInt(10));
    29 
    30         // 打印出map
    31         System.out.println("map:"+map );
    32 
    33         // 通过Iterator遍历key-value
    34         Iterator iter = map.entrySet().iterator();
    35         while(iter.hasNext()) {
    36             Map.Entry entry = (Map.Entry)iter.next();
    37             System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
    38         }
    39 
    40         // HashMap的键值对个数        
    41         System.out.println("size:"+map.size());
    42 
    43         // containsKey(Object key) :是否包含键key
    44         System.out.println("contains key two : "+map.containsKey("two"));
    45         System.out.println("contains key five : "+map.containsKey("five"));
    46 
    47         // containsValue(Object value) :是否包含值value
    48         System.out.println("contains value 0 : "+map.containsValue(new Integer(0)));
    49 
    50         // remove(Object key) : 删除键key对应的键值对
    51         map.remove("three");
    52 
    53         System.out.println("map:"+map );
    54 
    55         // clear() : 清空HashMap
    56         map.clear();
    57 
    58         // isEmpty() : HashMap是否为空
    59         System.out.println((map.isEmpty()?"map is empty":"map is not empty") );
    60     }
    61 }
    复制代码

     (某一次)运行结果: 

    复制代码
    map:{two=7, one=9, three=6}
    next : two - 7
    next : one - 9
    next : three - 6
    size:3
    contains key two : true
    contains key five : false
    contains value 0 : false
    map:{two=7, one=9}
    map is empty
  • 相关阅读:
    初识 visJs (基于html5 canvas开发的可视化框架)
    VueJs
    VueJS 使用i18n做国际化切换中英文
    vue-cli项目接口地址可配置化(多环境部署)一处修改多处适用
    vue + element-ui 制作下拉菜单(可配置路由、可根据路由高亮list、可刷新自动展开定位路由)
    vue-cli -- > 项目基本构建的方法
    javascript代码工具库
    HTML5新功能之六 《Web通信、WebSockets和跨文档消息传输》
    《响应式Web设计:HTML5和CSS3实战》 读书笔记
    HTML5新功能之二 《Geolocation获取地理位置》
  • 原文地址:https://www.cnblogs.com/yangj-Blog/p/12952744.html
Copyright © 2011-2022 走看看