高效的方式反转以使用少量键映射到相同值来反转散列映射

时间:2015-10-09 18:50:29

标签: java arraylist data-structures collections hashmap

我有一个哈希图,我知道有些键映射到相同的值 这些键的数量非常小(小于6%),它们映射在2-4个值之间 例如。

Map<String, String> map = new HashMap<>();  
map.put("codeA", "100");  
map.put("codeB", "7");  
map.put("codeC", "0012");   

我需要从值到键创建此映射的反转,所以我做了:

inverseMap = new HashMap<String, ArrayList<String>>();
for(Map.Entry<String, String> e:map.entrySet()) {
    String code = e.getKey();
    String val = e.getValue();
    ArrayList<String> codesColliding = inverseMap.get(val);
    if(codesColliding == null) {
        codesColliding = new ArrayList<>(4);
        inverseMap.put(val, codesColliding);
    }
    codesColliding.add(code);
}  

这有效,但我认为它不是最理想的,因为我使用的内存超过绝大多数键所需的内存。
虽然从编码的角度看它是有效的,但我想知道这是否可以采用不同的方式(通过其他数据结构?) 注意:我对普通的Java 7(没有额外的库)方法感兴趣

3 个答案:

答案 0 :(得分:2)

如果逆映射的值需要能够容纳来自原始映射的多个键,那么相对于它们不需要如此容纳的情况,没有避免一些开销。你当前的方法并不差,但是如果原始地图的价值的这么小的一部分是重复的,并且没有重复超过几次,那么我对你使用的列表的初始容量更加吝啬作为逆映射中的值。为什么预分配任何多个元素?您很少需要重新分配,但是当您这样做时,列表将透明地处理它。

答案 1 :(得分:0)

也许最简单的方法是创建一个具有两个HashMaps的类,一个用于非碰撞键,另一个用于碰撞的键。如果以某种方式消除碰撞的歧义(例如,您总是按字母顺序选择第一个),则可以将该逻辑添加到类中。或者,如果要返回ArrayLists,可以懒惰地将非碰撞字符串包装到ArrayList中。

这一切都是为了知道你想要用Map做什么。如果您确信您的代码可以处理String和ArrayList结果之间的歧义,您甚至可以牺牲一些类型的安全性。

答案 2 :(得分:0)

我知道你在谈论Map<String,String>,但为了清楚起见,我们将其概括为Map<K,V>,您正在构建Map<V,Collection<K>>。添加另一个Map<V,K>,也许称之为uniqueInverseMap。在浏览条目时,请务必先在inverseMap,然后uniqueInverseMap中检查密钥。如果它已经在uniqueInverseMap中,请将其删除,创建一个新的双元素列表,将列表添加到inverseMap