zoukankan      html  css  js  c++  java
  • HashMap与Hashtable的分析

    HashTable与HashMap概念

    基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。另外,HashMap是非线程安全的,也就是说在多线程的环境下,可能会存在问题,而Hashtable是线程安全的

    我们先来说HashTable  它的底层是用数据+链表实现的,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低。

     

     HashTable

    1、基本方法实现

            //创建一个HashTable实例
            Hashtable<Integer, Object> ht=new Hashtable<>();
            
            //key键是唯一的、value可以重复
            ht.put(1, "A");
            ht.put(2, "B");
            ht.put(3, "C");
            ht.put(4, "D");
            
            if(ht.contains("C")) {
                //判断哈希表表中是否包含特定律、返回值是true或者false
            }
            
            //移除一个key或者值
            ht.remove("C");
            
            //移除所有元素
            ht.clear();

    2、排序方式

     Hashtable ht = new Hashtable();
      ht.Add("a", 5);
      ht.Add("b", 22);
      ht.Add("c", 16);

    2.1   使用 ArrayList 数组排序 

    ArrayList al = new ArrayList(ht.Keys);
      al.Sort();
      1)按键升序输出
      for(int i = 0; i < al.Count; i++)
            Response.Write("键:" + al[i] + " 的值为:" + ht[al[i]].ToString() + "<br />");
      输出结果:
      键:a 的值为:5
      键:b 的值为:22
      键:c 的值为:16
     
      2)按键降序输出
      for(int i = al.Count - 1; i >= 0; i--)
            Response.Write("键:" + al[i] + " 的值为:" + ht[al[i]].ToString() + "<br />");
      输出结果:
      键:c 的值为:16
      键:b 的值为:22
      键:a 的值为:5

    2.2  使用 Array 数组按值排序

    string[] arrKey = new string[ht.Count];//暂存 Hashtable 的键
      int[] arrValue = new int[ht.Count];//暂存 Hashtable 的值
      ht.Keys.CopyTo(arrKey, 0);
      ht.Values.CopyTo(arrValue, 0);
      Array.Sort(arrValue, arrKey);//按 HashTable 的值排序
      for(int i = 0; i < arrKey.Length; i++)
            Response.Write("键:" + arrKey[i].ToString() + " 的值为:" + arrValue[i].ToString() + "<br />");
      输出结果:
      键:a 的值为:5
      键:c 的值为:16
      键:b 的值为:22

    2.3  使用 DataTable 按键或值排序

    DataTable dt = new DataTable();
      dt.Columns.Add("htKey", typeof(string));
      dt.Columns.Add("htValue", typeof(int));
      IDictionaryEnumerator ide = ht.GetEnumerator();
      while (ide.MoveNext())
      {
            DataRow dr = dt.NewRow();
            dr["htKey"] = ide.Key.ToString();
            dr["htValue"] = ide.Value.ToString();
            dt.Rows.Add(dr);
      }
      DataView dv = dt.DefaultView;
      dv.Sort = "htValue Desc";//此处是按值降序排列
      DataTable dt1 = dv.ToTable();
      for (int i = 0; i < dt1.Rows.Count; i++)
            Response.Write("键:" + dt1.Rows[i]["htKey"].ToString() + " 的值为:" + dt1.Rows[i]["htValue"].ToString() + "<br/>");
      输出结果:
      键:b 的值为:22
      键:c 的值为:16
      键:a 的值为:5

    3、增长因子

    • 初始size为11,扩容:newsize = olesize*2+1
    • 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

    HashMap

    1、map 键值对   json格式  根据你的键名来获取对应的值

    Map<String,Object> m=new HashMap<>();
            m.put("zh", "中国");
            m.put("en", "英国");
            m.put("jp", "日本");
            m.put("mg", "美国");
            if(!m.containsKey("zh")) {
                m.put("zh", "大中国");            
            }
            
            //排序    是按照值的第一个字母来   A-Z   排序
            System.out.println(m);
            
            //1、重复的key会有什么样子的问题
            //key相同则覆盖value值、以最后一个加入进去的值为真
            
            //2、如果值相同  而key不同 又会成为什么?
            //值相同、而键不同    则创建两个
            //键值对关系    只和键挂钩   而和值无关

    2、map集合的遍历方式

    Map<Integer,Object> m=new HashMap<>();
            //避免出现重复的值
            
            for(int i=0;i<10;i++) {
                if(!m.containsKey(i)) {
                    m.put(i, "z"+i);
                }
            }
            
            System.out.println(m.get(0));
            
            for(Integer i:m.keySet()) {
                System.out.println(i);
            }
            
            
            for(Object o:m.values()) {
                System.out.println(o);
            }

    2.1  HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。

    for(Entry<Integer, Object>  emp:m.entrySet()) {
                System.out.println("key:"+emp.getKey()+"value:"+emp.getValue());
            }
    //Entry输出
    key:0value:z0
    key:1value:z1
    key:2value:z2
    key:3value:z3
    key:4value:z4
    key:5value:z5
    key:6value:z6
    key:7value:z7
    key:8value:z8
    key:9value:z9
    
    //普通输出
    {0=z0, 1=z1, 2=z2, 3=z3, 4=z4, 5=z5, 6=z6, 7=z7, 8=z8, 9=z9}

    3、  HashMap的初始值还要考虑加载因子

    • 哈希冲突:若干Key的哈希值按数组大小取模后,如果落在同一个数组下标上,将组成一条Entry链,对Key的查找需要遍历Entry链上的每个元素执行equals()比较。
    • 加载因子:为了降低哈希冲突的概率,默认当HashMap中的键值对达到数组大小的75%时,即会触发扩容。因此,如果预估容量是100,即需要设定100/0.75=134的数组大小。
    • 空间换时间:如果希望加快Key查找的时间,还可以进一步降低加载因子,加大初始大小,以降低哈希冲突的概率。

    总结一下:

    1. HashMap和Hashtable都是用hash算法来决定其元素的存储,因此HashMap和Hashtable的hash表包含如下属性
    2. 容量(capacity):hash表中桶的数量
    3. 初始化容量(initial capacity):创建hash表时桶的数量,HashMap允许在构造器中指定初始化容量
    4. 尺寸(size):当前hash表中记录的数量
    5. 负载因子(load factor):负载因子等于“size/capacity”。负载因子为0,表示空的hash表,0.5表示半满的散列表,依此类推。轻负载的散列表具有冲突少、适宜插入与查询的特点(但是使用Iterator迭代元素时比较慢)
    6. 除此之外,hash表里还有一个“负载极限”,“负载极限”是一个0~1的数值,“负载极限”决定了hash表的最大填满程度。当hash表中的负载因子达到指定的“负载极限”时,hash表会自动成倍地增加容量(桶的数量),并将原有的对象重新分配,放入新的桶内,这称为rehashing。
    7. HashMap和Hashtable的构造器允许指定一个负载极限,HashMap和Hashtable默认的“负载极限”为0.75,这表明当该hash表的3/4已经被填满时,hash表会发生rehashing。
  • 相关阅读:
    jquery+ajax+ashx。ashx的使用方法
    如何在ashx页面获取Session值
    模式DIV。
    .net 中文传参
    5分钟无操作,退出,操作方法,关闭页面
    SQL Server DATEDIFF() 函数(SQL计算时间差)
    Sql server 事务的两种用法
    正则表达式相关
    jQuery AJAX实现调用页面后台方法。调用ashx方法
    时间差(类.精确到秒).net中实现Datediff类C#
  • 原文地址:https://www.cnblogs.com/wshemin/p/10906861.html
Copyright © 2011-2022 走看看