zoukankan      html  css  js  c++  java
  • Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

    Writer:BYSocket(泥沙砖瓦浆木匠)

    微博:BYSocket

    豆瓣:BYSocket

    Java 容器的文章这次应该是最后一篇了:Java 容器 系列。 今天泥瓦匠聊下 Maps。

    一、Map回顾

        Map,又称映射表,是将键映射到值的对象。有四种实现Map接口并且经常使用的Map集合为:HashMap,TreeMap,Hashtable 和 LinkedHashMap.

    泥瓦匠记忆宫殿:

        1、一个映射不包含重复的键

        2、每个键最多只能映射到一个值。

    MapClassHierarchy-600x354

    二、HashMap

        HashMap是基于哈希表的Map接口的实现。其对键进行散列,散列函数只能作用于键。下面模拟下,公司员工和找员工的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import java.util.HashMap;
    import java.util.Map;
     
    class Employee
    {}
     
    public class HaspMap01
    {
        public static void main(String[] args)
        {
            Map<String, Employee> employees = new HashMap<String, Employee>();
            employees.put("1206010035", new Employee());
            System.out.println(employees);
             
            String number = "1206010035";
            System.out.println(employees.get(number));
        }
    }

    Run一下,大家可以见到结果:put方法,可以将键值映射添加进表。get方法则返回指定键所映射的值。从他们 hashCode 可以看出是同一个对象。

        HaspMap的键必须唯一,同样其同一个键不能存放两个值,如果对同一个键两次调用put方法,第二个值会取代第一个值。同样是允许使用 null 值和 null 键。下面泥瓦匠用一个简单的例子解释下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package javaBasic.collection.map;
     
    import java.util.HashMap;
    import java.util.Map;
     
     
    public class HaspMap02
    {
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public static void main(String[] args)
        {
            Map map = new HashMap<String, String>();
            map.put(null, "null01");
            map.put(null, "null02");
            System.out.println(map);
            System.out.println(map.get(null));
        }
    }

    结果如下:

    1
    2
    {null=null02}
    null02

    由此可见,第一个值被第二个值所替换了。

    下面有三点是HashMap重要之处:

    1、HashMap的构造函数

       HaspMap构造函数涉及两个参数:初始容量和加载因子。初试容量是哈希表创建时的其中桶的含量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。这两个参数都是影响HashMap的性能。默认构造一个具有默认初始容量 (16) 和默认加载因子 (0.75)。默认加载因子 (.75) 在时间和空间成本上是一种折衷的考虑。

    2、和上次总结的Set都差不多,这个HashMap线程是不安全不同步的。如果想防止意外发生,则设置成同步即可:

    1
    Map m = Collections.synchronizedMap(new HashMap(...));

    3、不同步的话,意味着存在快速失败导致的并发修改异常。

    下面看一个复杂例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    package javaBasic.collection.map;
     
    import java.util.HashMap;
    import java.util.Map.Entry;
     
    class A
    {
        public boolean equals(Object obj)
        {
            return true;
        }
    }
     
    class B
    {
        public int hashCode()
        {
            return 1;
        }
    }
     
    class C
    {
        public int hashCode()
        {
            return 2;
        }
     
        public boolean equals(Object obj)
        {
            return true;
        }
    }
     
    public class HashMap03
    {
        public static void main(String[] args)
        {
            HashMap<A, Integer> hashMapA = new HashMap<A, Integer>();
            hashMapA.put(new A(), 10);
            hashMapA.put(new A(), 5);
             
            System.out.println("HashMapA Elements:");
            System.out.print(" " + hashMapA + " ");
             
            // loop HashMapA
            for(Entry<A, Integer> entryA : hashMapA.entrySet())
            {
                System.out.println(entryA.getKey().toString()+"-"+entryA.getValue());
            }
             
            HashMap<B, Integer> hashMapB = new HashMap<B, Integer>();
            hashMapB.put(new B(), 10);
            hashMapB.put(new B(), 5);
             
            System.out.println("HashMapB Elements:");
            System.out.print(" " + hashMapB + " ");
             
            // loop HashMapB
            for(Entry<B, Integer> entryB : hashMapB.entrySet())
            {
                System.out.println(entryB.getKey().toString()+"-"+entryB.getValue());
            }
             
            HashMap<C, Integer> hashMapC = new HashMap<C, Integer>();
            hashMapC.put(new C(), 10);
            hashMapC.put(new C(), 5);
             
            System.out.println("HashMapC Elements:");
            System.out.print(" " + hashMapC + " ");
             
            // loop HashMap
            for(Entry<C, Integer> entryC : hashMapC.entrySet())
            {
                System.out.println(entryC.getKey().toString()+"-"+entryC.getValue());
            }
        }
    }

    运行一下,可以看到以下结果:

     

    由此可见,其中和 Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较 中涉及的知识点一致:

    集合判断两个元素相等不单单是equals方法,并且必须hashCode()方法返回值也要相等。


    三、TreeMap

        TreeMap使用树结构实现(红黑树),集合中的元素进行排序,但是添加、删除和包含的算法复杂度为O(log(n))。其实Map特性基本都是一致的,比如看下面的简单例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class TreeMap01
    {  
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public static void main(String[] args)
        {
            Map map = new TreeMap();
            map.put("1", "1");
            map.put("4", "4");
            map.put("2", "2");
            map.put("2", "3");
            System.out.println(map);
        }
    }

    结果如下:

    1
    {1=1, 2=3, 4=4}

    从中我们可以看出

    1、TreeMap实现了SortedMap,顾名思义,其表示为有排序的集合。

    2、同样其同一个键不能存放两个值,如果对同一个键两次调用put方法,第二个值会取代第一个值。

    四、总结

    HashMap与TreeMap
          1、HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。HashMap中元素的排列顺序是不固定的)。
          2、  HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。
          3、在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。 这个TreeMap没有调优选项,因为该树总处于平衡状态。

    Writer:BYSocket(泥沙砖瓦浆木匠)

    微博:BYSocket

    豆瓣:BYSocket

  • 相关阅读:
    ZOJ 3891 K-hash
    ZOJ 3890 Wumpus
    ZOJ 3888 Twelves Monkeys
    ZOJ 3885 The Exchange of Items
    HDU 3849 By Recognizing These Guys, We Find Social Networks Useful
    HDU 2242 考研路茫茫——空调教室
    BZOJ 3676: [Apio2014]回文串
    [转载]CAsyncSocket及CSocket注解
    WritePrivateProfileString()
    GetSystemMetrics()
  • 原文地址:https://www.cnblogs.com/Alandre/p/4478815.html
Copyright © 2011-2022 走看看