HashMap,LinkedHashMap和TreeMap之间的区别


958

是什么区别HashMapLinkedHashMapTreeMap在Java中?我没有看到输出的任何差异,因为这三个都有keySetvalues。什么是Hashtables?

Map m1 = new HashMap();
m1.put("map", "HashMap");
m1.put("schildt", "java2");
m1.put("mathew", "Hyden");
m1.put("schildt", "java2s");
print(m1.keySet()); 
print(m1.values()); 

SortedMap sm = new TreeMap();
sm.put("map", "TreeMap");
sm.put("schildt", "java2");
sm.put("mathew", "Hyden");
sm.put("schildt", "java2s");
print(sm.keySet()); 
print(sm.values());

LinkedHashMap lm = new LinkedHashMap();
lm.put("map", "LinkedHashMap");
lm.put("schildt", "java2");
lm.put("mathew", "Hyden");
lm.put("schildt", "java2s");
print(lm.keySet()); 
print(lm.values());

Answers:


1160

这三个类都实现了该Map接口,并提供了几乎相同的功能。最重要的区别是遍历条目的顺序:

  • HashMap绝对不保证迭代顺序。添加新元素时,它甚至可以(并将)完全改变。
  • TreeMap将根据密钥的“自然顺序”(根据其compareTo()方法)(或外部提供的Comparator)进行迭代。此外,它实现了SortedMap接口,该接口包含依赖于此排序顺序的方法。
  • LinkedHashMap 将按照条目放入地图的顺序进行迭代

“哈希表”是基于哈希的映射的通用名称。在Java API的上下文中, Hashtable是从Java 1.1到集合框架存在之前的过时的类。不再使用它,因为它的API充满了重复功能的过时方法,并且它的方法是同步的(这会降低性能,并且通常是无用的)。使用ConcurrentHashMap而不是Hashtable。


2
那么Map实际上是什么,以及Map,HashMap和Hashtables之间的区别是什么。
凯文

5
@theband:Map是一个接口。HashMap和Hashtable都实现了它;如我所写,Hashtable是一个遗留类。
Michael Borgwardt 2010年

98
Hashtable和之间的一个显着区别HashMap是在哈希表中,“键或值都不能为空”。后者不存在此约束。
aioobe

4
@AshkanN:是的-实际上,这些是实现排序的标准方法。TreeMap具有一个使用Comparator的构造函数,并且如果未提供任何构造函数,则它期望添加所有对象以实现Comparable。
Michael Borgwardt

4
您可以选择是否要以插入顺序或访问顺序进行LinkedHashMap迭代。
lbalazscs 2014年

1606

我更喜欢视觉呈现:

╔══════════════╦═════════════════════╦═══════════════════╦═════════════════════╗
║   Property   ║       HashMap       ║      TreeMap      ║     LinkedHashMap   ║
╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣
║ Iteration    ║  no guarantee order ║ sorted according  ║                     ║
║   Order      ║ will remain constant║ to the natural    ║    insertion-order  ║
║              ║      over time      ║    ordering       ║                     ║
╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣
║  Get/put     ║                     ║                   ║                     ║
║   remove     ║         O(1)        ║      O(log(n))    ║         O(1)        ║
║ containsKey  ║                     ║                   ║                     ║
╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣
║              ║                     ║   NavigableMap    ║                     ║
║  Interfaces  ║         Map         ║       Map         ║         Map         ║
║              ║                     ║    SortedMap      ║                     ║
╠══════════════╬═════════════════════╬═══════════════════╬═════════════════════╣
║              ║                     ║                   ║                     ║
║     Null     ║       allowed       ║    only values    ║       allowed       ║
║ values/keys  ║                     ║                   ║                     ║
╠══════════════╬═════════════════════╩═══════════════════╩═════════════════════╣
║              ║   Fail-fast behavior of an iterator cannot be guaranteed      ║
║   Fail-fast  ║ impossible to make any hard guarantees in the presence of     ║
║   behavior   ║           unsynchronized concurrent modification              ║
╠══════════════╬═════════════════════╦═══════════════════╦═════════════════════╣
║              ║                     ║                   ║                     ║
║Implementation║      buckets        ║   Red-Black Tree  ║    double-linked    ║
║              ║                     ║                   ║       buckets       ║
╠══════════════╬═════════════════════╩═══════════════════╩═════════════════════╣
║      Is      ║                                                               ║
║ synchronized ║              implementation is not synchronized               ║
╚══════════════╩═══════════════════════════════════════════════════════════════╝

14
除了插入顺序外,LinkedHashMap还支持访问顺序(将构造函数与布尔访问顺序参数一起使用时)。
Eyal Schneider

5
双链桶?我认为这增加了搜索存储桶以进行插入/移除操作的不必要开销(因为它必须搜索正确的存储桶才能放入对象)。我一直认为LinkedHashMap的实现与Map的实现类似,但是用于迭代目的的“条目列表”(可能是链接列表)的额外开销很小。确定吗,舍甫克?如果是,您能否解释或给我一些支持您声明的在线链接?
赛杜巴卡2014年

5
@SaiDubbaka LinkedHashMap具有双链接存储桶,但存储桶表HashMap也具有。它不是替代它。这意味着访问存储桶的方式与HashMap中的存储方式相同,因为链表仅按插入顺序(或访问顺序)进行迭代。
Gerardo Lastra

5
值得一提的是,O(1)是最好的情况(我们通常不称其为O,请参见此问题
Sebastian S

4
还值得注意的是,O(1)并不总是比O(log n)好;如果您有一个很长的密钥,则基于BST的操作可能比必须对整个密钥执行O(n)哈希处理的操作要快得多。
基金莫妮卡的诉讼

65

这三个代表从唯一键到值的映射,因此实现了Map接口。

  1. HashMap是基于键哈希的映射。它支持O(1)get / put操作。密钥必须具有一致的实现,hashCode()并且equals()才能正常工作。

  2. LinkedHashMap与HashMap非常相似,但是它增加了添加(或访问)项目的顺序的意识,因此迭代顺序与插入顺序(或访问顺序,取决于构造参数)相同。

  3. TreeMap是基于树的映射。其放置/获取操作花费O(log n)时间。它要求项目具有可比较或比较器的某种比较机制。迭代顺序由此机制确定。


1
因此,如果我理解正确,鉴于插入顺序与自然顺序相同,LinkedHashMap和TreeMap的唯一区别就是性能?
Moshe Shaham 2012年

19
@MosheShaham正如他在#2中所述:LinkedHashMap将按插入顺序而不是自然顺序进行迭代。因此,如果您添加(2,5,3)到a LinkedHashMap并对其进行每个操作,它将返回2,5,3。如果是2,5,3TreeMap它将返回2,3,5
grinch 2013年

2
树图还具有许多其他不错的技巧。像头和尾图。
Thomas Ahle 2014年

私有TreeMap <String,Integer> mySection2 = new TreeMap <>(); mySection2.put(“ abc1”,2); mySection2.put(“ abc2”,5); mySection2.put(“ abc3”,3); for(Integer x:mySection2.values()){Log.e(“ LOG”,“ TreeMap ====” + x); 这给了我与插入项目相同的顺序?请建议它与LinkedHashMaps有何不同?
B.shruti

2
@ B.shruti:这是因为您的插入顺序与键的字典顺序(“ abc1”,“ abc2”,“ abc3”)匹配。如果您以不同的顺序插入,您的代码仍将根据字典顺序进行迭代。
Eyal Schneider

47

在下图中查看每个类在类层次结构中的位置(图)。TreeMap实现SortedMapNavigableMapHashMap没有实现。

HashTable已过时,ConcurrentHashMap应使用相应的类。 在此处输入图片说明


38

哈希图

  • 它具有对值(键,值)
  • 没有重复键值
  • 无序的
  • 它允许一个空键和一个以上的空值

哈希表

  • 与哈希图相同
  • 它不允许空键和空值

LinkedHashMap

  • 它是地图实现的有序版本
  • 基于链表和哈希数据结构

树状图

  • 订购和分类版本
  • 基于哈希数据结构

3
HashTable也是同步的。无论如何,我喜欢您的回答,干净清晰。
Surasin Tancharoen 2015年

35

从我自己在使用地图时的经验中获得的更多信息,包括:

  • HashMap-在寻找最佳性能(快速)实现时最有用。
  • TreeMap(SortedMap接口)-当我担心能够按我定义的特定顺序对键进行排序或迭代时,此功能最为有用。
  • LinkedHashMap-结合了从TreeMap保证有序订购的优点,而又不增加维护TreeMap的成本。(它几乎与HashMap一样快)。特别是,LinkedHashMap还通过重写removeEldestEntry()方法为创建Cache对象提供了一个很好的起点。这使您可以创建一个Cache对象,该对象可以使用您定义的某些条件使数据过期。

10
确切地说,TreeMap不会使元素保持顺序。它使按键保持顺序。
LS 2013年

17

所有这三个班HashMapTreeMapLinkedHashMap工具java.util.Map接口,以及代表唯一关键值映射。

哈希图

  1. A HashMap包含基于键的值。

  2. 它仅包含唯一元素。

  3. 它可能具有一个null键和多个null值。

  4. 它不保持任何顺序

    public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

LinkedHashMap

  1. A LinkedHashMap包含基于键的值。
  2. 它仅包含唯一元素。
  3. 它可能具有一个null键和多个null值。
  4. 与HashMap相同,只是保持插入顺序//请参见下面的类减速

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>

树状图

  1. A TreeMap包含基于键的值。它实现了NavigableMap接口并扩展了AbstractMap类。
  2. 它仅包含唯一元素。
  3. 它不能具有null键,但可以具有多个null值。
  4. HashMap保持升序相同(使用其键的自然顺序排序)。

    public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, Serializable

哈希表

  1. 哈希表是列表的数组。每个列表称为存储桶。桶的位置通过调用hashcode()方法来标识。哈希表包含基于键的值。
  2. 它仅包含唯一元素。
  3. 它可能没有任何空键或值。
  4. 它是同步的
  5. 这是一个遗留类。

    public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable

参考:http : //javarevisited.blogspot.in/2015/08/difference-between-HashMap-vs-TreeMap-vs-LinkedHashMap-Java.html


HashMap的Big-O表示法不应为O(1)。那是最好的情况,哈希表以O(n)作为最坏的情况。您的链接支持此功能。
HaakonLøtveit'17


@HaakonLøtveit我还将建议在此处获取实际代码-grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…–
roottraveller

STILL表示在最坏的情况下为O(n)。这是一个数学概念,您不必说它是O(1),除非它实际上是O(1)。您还假设这里有一些非常好的哈希函数。我的意思是,我们可以使用类似类TerribleHashKey {@Override hashCode(){return 4; / *由掷骰子确定* /}},并将其用作其他有趣内容的键。O(1)的概率很高,O(1)的概率不同。人们来这里寻求作业帮助。让我们不要破坏他们的成绩..;)
HaakonLøtveit17年

值得注意的是,在Java 8中,如果存储桶数超过8,则O(log(n))的情况最糟,请参阅grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk /…有关此的详细信息。
HaakonLøtveit17年

14

HashMap绝对不保证迭代顺序。添加新元素时,它甚至可以(并将)完全改变。TreeMap将根据键的compareTo()方法(或外部提供的Comparator)根据键的“自然顺序”进行迭代。此外,它实现了SortedMap接口,该接口包含依赖于此排序顺序的方法。LinkedHashMap将按照将条目放入地图的顺序进行迭代

看一下性能如何变化。 在此处输入图片说明

树图是已排序图的实现。由于自然排序,put,get和containsKey操作的复杂度为O(log n)


9

@Amit:SortedMap是一个接口,TreeMap而是一个实现该SortedMap接口的类。这意味着是否遵循SortedMap要求其实现者执行的协议。除非实现为搜索树,否则树无法提供有序数据,因为树可以是任何种类的树。因此,为了使TreeMap像Sorted Order一样工作,它实现了SortedMap(例如Binary Search Tree-BST,诸如AVL和RB Tree的Balanced BST,甚至Ternary Search Tree-主要用于有序搜索)。

public class TreeMap<K,V>
extends AbstractMap<K,V>
implements SortedMap<K,V>, Cloneable, Serializable

在NUT-SHELL中 HashMap:以O(1)给出数据,无顺序

TreeMap :以基数2以O(log N)给出数据。

LinkedHashMap:是具有链接列表(认为是indexed-SkipList)功能的哈希表,以将数据插入树中的方式存储数据。最适合实现LRU(最近最少使用)。


6

以下是HashMap和TreeMap之间的主要区别

  1. HashMap不维护任何顺序。换句话说,HashMap不能保证首先插入的元素将被首先打印,就像TreeSet一样,TreeMap元素也根据其元素的自然顺序进行排序。

  2. 内部HashMap实现使用哈希,而TreeMap内部使用Red-Black树实现。

  3. HashMap可以存储一个null键和许多null值。TreeMap不能包含null键,但可以包含许多null值。

  4. HashMap对诸如get和put即O(1)之类的基本操作具有恒定的时间性能。根据Oracle文档,TreeMap为get和put方法提供了保证的log(n)时间成本。

  5. HashMap比TreeMap快得多,因为对于大多数操作,HashMap的性能时间与TreeMap的日志时间是恒定的。

  6. HashMap在比较中使用equals()方法,而TreeMap在使用compareTo()方法维护排序。

  7. HashMap实现Map接口,而TreeMap实现NavigableMap接口。


5

这些是同一接口的不同实现。每个实现都有其优点和缺点(快速插入,慢速搜索),反之亦然。

有关详细信息,请参见TreeMapHashMapLinkedHashMap的javadoc 。


哈希表实际上是什么,它与地图有何不同。
凯文

5

哈希图不保留插入顺序。
例。Hashmap如果您要插入密钥

1  3
5  9
4   6
7   15
3   10

它可以存储为

4  6
5  9
3  10
1  3
7  15

链接的哈希图保留插入顺序。

例。
如果要插入密钥

1  3
5  9
4   6
7   15
3   10

它将存储为

1  3
5  9
4   6
7   15
3   10

与我们插入的相同。

树状图按键的递增顺序存储值。例。
如果要插入密钥

1  3
5  9
4   6
7   15
3   10

它将存储为

1  3
3  10
4   6
5   9
7   15

4
  • HashMap:

    • 订单无法维持
    • 比LinkedHashMap更快
    • 用于存储对象堆
  • LinkedHashMap:

    • LinkedHashMap的插入顺序将保持不变
    • 比HashMap慢,比TreeMap快
    • 如果要维护插入顺序,请使用此命令。
  • TreeMap:

    • TreeMap是基于树的映射
    • TreeMap将遵循键的自然顺序
    • 比HashMap和LinkedHashMap慢
    • 当您需要保持自然(默认)顺序时使用TreeMap

1

它们都提供了一个键->值映射以及一种遍历键的方法。这些类之间最重要的区别是时间保证和密钥的顺序。

  1. HashMap提供0(1)查找和插入。但是,如果您遍历键,则键的顺序本质上是任意的。它由一系列链接列表实现。
  2. TreeMap提供O(log N)查找和插入。密钥是有序的,因此,如果需要按排序顺序遍历密钥,则可以。这意味着键必须实现Comparable接口.TreeMap由Red-Black Tree实现。
  3. LinkedHashMap提供0(1)查找和插入。密钥按其插入顺序排序。它是通过双链桶实现的。

假设您将空的TreeMap,HashMap和LinkedHashMap传递给以下函数:

void insertAndPrint(AbstractMap<Integer, String> map) {
  int[] array= {1, -1, 0};
  for (int x : array) {
    map.put(x, Integer.toString(x));
  }
  for (int k: map.keySet()) {
   System.out.print(k + ", ");
  }
}

每个的输出将类似于以下结果。

对于HashMap,在我自己的测试中,输出为{0,1,-1},但可以是任何顺序。不能保证订购。
树状图,输出为{-1,0,1}
LinkedList,输出为{1,-1,0}


1

尽管这里有很多出色的Answers,但我想展示自己的表格,描述Map与Java 11捆绑在一起的各种实现。

我们可以在表格图形中看到这些差异:

  • HashMap是您没有特殊需要时通常使用的通用用途 Map
  • LinkedHashMap扩展HashMap,添加以下行为:保持顺序,即最初添加条目顺序。更改键值输入的值不会更改其在顺序中的位置。
  • TreeMap也保持顺序,但使用(a)“自然”顺序,即接口compareTo上定义的键对象上方法的值Comparable,或(b)调用您提供Comparator实现
  • NULL S:TreeMap没有允许NULL作为重点,而HashMapLinkedHashMap做。
    • 这三个都允许NULL作为值。
  • HashTableJava 遗留下来的。由ConcurrentHashMap班级取代。引用Javadoc:ConcurrentHashMap遵循与相同的功能规范Hashtable,并包括与的每个方法相对应的方法版本Hashtable

Java 11中的地图实现表,比较它们的功能


0

HashMap
可以包含一个空键。

HashMap不维护任何顺序。

树状图

TreeMap不能包含任何空键。

TreeMap保持升序。

LinkedHashMap

LinkedHashMap可用于维护插入顺序(在该插入顺序上将密钥插入到Map中),LinkedHashMap也可用于维护访问顺序(在该顺序上可访问密钥)。

范例 ::

1)HashMap map = new HashMap();

    map.put(null, "Kamran");
    map.put(2, "Ali");
    map.put(5, "From");
    map.put(4, "Dir");`enter code here`
    map.put(3, "Lower");
    for (Map.Entry m : map.entrySet()) {
        System.out.println(m.getKey() + "  " + m.getValue());
    } 

2)TreeMap map = new TreeMap();

    map.put(1, "Kamran");
    map.put(2, "Ali");
    map.put(5, "From");
    map.put(4, "Dir");
    map.put(3, "Lower");
    for (Map.Entry m : map.entrySet()) {
        System.out.println(m.getKey() + "  " + m.getValue());
    }

3)LinkedHashMap map = new LinkedHashMap();

    map.put(1, "Kamran");
    map.put(2, "Ali");
    map.put(5, "From");
    map.put(4, "Dir");
    map.put(3, "Lower");
    for (Map.Entry m : map.entrySet()) {
        System.out.println(m.getKey() + "  " + m.getValue());
    }

0

这三者中最重要的是它们如何保存条目的顺序。

HashMap-不保存输入顺序。例如。

public static void main(String[] args){
        HashMap<String,Integer> hashMap = new HashMap<>();
        hashMap.put("First",1);// First ---> 1 is put first in the map
        hashMap.put("Second",2);//Second ---> 2 is put second in the map
        hashMap.put("Third",3); // Third--->3 is put third in the map
        for(Map.Entry<String,Integer> entry : hashMap.entrySet())
        {
            System.out.println(entry.getKey()+"--->"+entry.getValue());
        }
    }

HashMap的输出

LinkedHashMap:保存输入顺序。例如:

public static void main(String[] args){
        LinkedHashMap<String,Integer> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("First",1);// First ---> 1 is put first in the map
        linkedHashMap.put("Second",2);//Second ---> 2 is put second in the map
        linkedHashMap.put("Third",3); // Third--->3 is put third in the map
        for(Map.Entry<String,Integer> entry : linkedHashMap.entrySet())
        {
            System.out.println(entry.getKey()+"--->"+entry.getValue());
        }
    }

LinkedHashMap的输出

TreeMap:按键的升序保存条目。例如:

public static void main(String[] args) throws IOException {
        TreeMap<String,Integer> treeMap = new TreeMap<>();
        treeMap.put("A",1);// A---> 1 is put first in the map
        treeMap.put("C",2);//C---> 2 is put second in the map
        treeMap.put("B",3); //B--->3 is put third in the map
        for(Map.Entry<String,Integer> entry : treeMap.entrySet())
        {
            System.out.println(entry.getKey()+"--->"+entry.getValue());
        }
    }

TreeMap的输出

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.