HashMap应该是未分类的,但仍然按键排序

时间:2014-02-13 09:27:18

标签: java sorting data-structures hashmap

根据这些:

  1. http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html
  2. Difference between HashMap, LinkedHashMap and TreeMap
  3. java beginner : How key gets sorted in hashmaps?
  4. HashMap中的Java应该是未排序的,但是会根据Key进行排序。

    我认为这是一个问题,因为我需要插入订单数据。所以,我使用LinkedHashMap代替。但我仍然感到困惑,为什么HashMap对它进行了排序。

    任何人都可以解释一下吗?

    我做了一个简单的例子来查看排序。

    public static void main(String[] args) {
    
            HashMap<Integer, String> newHashMap = new HashMap<Integer, String>();
            newHashMap.put(2, "First");
            newHashMap.put(0, "Second");
            newHashMap.put(3, "Third");
            newHashMap.put(1, "Fourth");
    
            Iterator<Entry<Integer, String>> iterator = newHashMap.entrySet()
                    .iterator();
            while (iterator.hasNext()) {
    
                Map.Entry<Integer, String> entry = iterator.next();
                System.out.println("Key: " + entry.getKey());
                System.out.println("Value: " + entry.getValue());
                iterator.remove();
            }
    
        }
    

    结果:

    Key: 0
    Value: Second
    Key: 1
    Value: Fourth
    Key: 2
    Value: First
    Key: 3
    Value: Third
    

    修改

    我尝试使用Random的{​​{1}}插入50个随机数,我发现一些数据未排序。但是,它仍然设法对大多数整数进行排序。

    随机结果:

    Java

10 个答案:

答案 0 :(得分:5)

这是巧合(不是真的,而是与散列算法有关)。

尝试添加

newHashMap.put(-5, "Fifth");

最后一次。

输出

Key: 0
Value: Second
Key: 1
Value: Fourth
Key: 2
Value: First
Key: 3
Value: Third
Key: -5
Value: Fifth

javadoc特别说

  

此课程不保证地图的顺序;特别是,它不保证订单会随着时间的推移保持不变。

答案 1 :(得分:1)

这纯属巧合。有时出现进行排序,但不断添加键,梦想就会破碎。

我写了这个小程序:

import java.util.Map;
import java.util.HashMap;

class MapTest {

    public static void main(String[] args){
        int count = Integer.parseInt(args[0]);
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < count; i++) map.put(i, i);
        System.out.println(map);
    }

}

运行java MapTest 20时,我得到以下输出(为了便于阅读,换行):

{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10, 11=11, 12=12, 13=13, 
14=14, 15=15, 17=17, 16=16, 19=19, 18=18}

这只是HashMap实现的一个属性,Integer s顺序添加(从0开始)似乎是有序的。

答案 2 :(得分:1)

你不应该推断太多!仅仅因为三个或四个数字出现排序,这并不意味着已经排序。

正int的哈希码通常只是int,所以如果你的所有键都低于Map维护的内部数组的长度,它们可能会显示为已排序。

尝试使用非常大的值,您会看到令人失望的订单消失。例如,使用

100,200,300,100001,100002,10003,999123456,888777666,....

答案 3 :(得分:1)

你不能假设它会被排序。在这个简单的例子中,它出现排序的原因是:HashMap是从“Bins”内部构造的。这些箱包含实际元素。它们基本上是驻留在数组中的小列表。

[0] -> [ Bin0: ... ]
[1] -> [ Bin1: ... ]
[2] -> [ Bin2: ... ]
[3] -> [ Bin3: ... ] 

当一个项插入到HashMap中时,应该插入它的“Bin”是 - 通过使用对象的hashCode()作为数组索引来简化它。例如,如果hashCode是2,它将被插入到Bin 2.当这个“index”大于数组大小时,它将被放入Bin(索引%arraySize) - 也就是说,如果hashCode是5,它将插入Bin 1。

由于HashMap最初的内部数组大小为10,因此在0到9之间插入Integer个对象会巧合地将元素以正确的顺序放入数组中。 (当然,Integer的hashCode只是它的值)。

(注意:实际的算法和散列函数可能稍微复杂一点,但这是基本的想法)

答案 4 :(得分:1)

就像每个人都说的那样(并且正确)是你应该假设HashMap中的键没有排序。 现在他们LOOK按你的理由分类了两个简单的原因:

1 - 您正在使用Integer作为键HashMap使用Java的Object类的hashCode()方法来查找它使用的基础数组中的索引存储Entry个实例(包含HashMap中的值和键的内容。恰好,Integer的哈希码就是它自己的值。

2 - 您没有设置HashMap 的初始大小,因此使用其默认初始大小(即16)。因此,在添加低于0或高于16(包括)的键之前,您将看到按顺序存储的键。由于HashMap通过执行

获取索引
int index = newKey.hashCode() % this.capacity;

稍后HashMap可能会增加其基础数组的容量,如果你插入很多键值对(如果你进入算法和数据结构研究,它决定如何以及何时这样做非常有趣),因此,您最终可能会遇到Integer个键可能再次排序的情况,但实际上并未对它们进行有意排序。

顺便说一句,如果您的密钥将是整数,并且您可以估计您将要建议直接使用数组的最大密钥值。访问速度更快,使用的内存相同或略少。

答案 5 :(得分:0)

您不能对HashMap对象的排序做出假设。他们将根据需要订购,实施定义。您应该将它们视为无序数据结构。

答案 6 :(得分:0)

实际上无法确保订单。

Hashmap使用哈希码快速哈希数据以进行搜索。

你的钥匙很简单,所以它排序了。

答案 7 :(得分:0)

Mine是一个有根据的猜测,但原因很可能是默认的hashCode方法使用了内存位置。小Integer的内存位置(以及您的密钥被自动装入Integer)很可能是固定的:让Integer.valueOf(1)在多个呼叫上返回不同的内存位置是毫无意义的。最后,这些固定存储器位置很可能是按升序排列的。这可以解释这个巧合,但是,需要深入研究Integer和HashMap的实现来证明这一点。

更正:在Integer的情况下“此对象的哈希码值,等于此Integer对象表示的原始int值。” (JavaDoc的)。虽然数字不同,但确认了这个想法。

答案 8 :(得分:0)

由于没有真正用于查看Java源代码的答案,我会这样做! :)

当您调用put()函数时,内部散列函数使用对象的hashCode来生成散列索引。 [put() source]

hash()函数只是确保在每个位位置只有常数倍数的hashCodes具有有限的碰撞次数[使用Google查看为什么会这样]。

事情恰巧在这里奏效了。就是这样。

答案 9 :(得分:0)

提问者说:
“Java 中的 HashMap 应该是未排序的,但它是根据 Key 进行排序的。”
是,对的。我将向您展示以下示例

Map<String, String> map1 = new HashMap<String, String>();
map1.put("c","xxxx");
map1.put("b","yyyy");
map1.put("a","zzzz");
for (String key :map1.keySet())
  System.out.println(map1.get(key));

System.out.println();

Map<Integer,String> map2 = new HashMap<Integer,String>();
map2.put(3,"xxxx");
map2.put(2,"yyyy");
map2.put(1,"zzzz");
for (int key :map2.keySet())
  System.out.println(map2.get(key));

输出显示HashMap使用Key对数据进行排序

xxxx
yyyy
zzzz

zzzz
yyyy
xxxx