代码之家  ›  专栏  ›  技术社区  ›  Kip

Java是否有反向查找的哈希图?

  •  93
  • Kip  · 技术社区  · 15 年前

    我的数据是以“密钥”格式组织的,而不是“密钥值”。这就像一个哈希图,但我需要在两个方向上进行O(1)查找。这种类型的数据结构是否有名称,在Java的标准库中是否包含这样的数据结构呢?(或者可能是阿帕奇公地?)

    我可以编写自己的类,它基本上使用两个镜像映射,但我不想重新发明轮子(如果这个已经存在,但我只是没有寻找合适的术语)。

    7 回复  |  直到 6 年前
        1
  •  103
  •   dARKpRINCE    10 年前

    在Java API中没有这样的类。您想要的ApacheCommons类将成为 BidiMap .

    作为一个数学家,我将这种结构称为双射。

        2
  •  72
  •   Abdull David Silva Smith    6 年前

    除了阿帕奇公地, Guava 也有一个 BiMap .

        3
  •  19
  •   GETah Mike Zboray    13 年前

    这里有一个简单的类,我过去常常这样做(我还不想有另一个第三方依赖)。它并没有提供地图中所有可用的功能,但它是一个良好的开端。

        public class BidirectionalMap<KeyType, ValueType>{
            private Map<KeyType, ValueType> keyToValueMap = new ConcurrentHashMap<KeyType, ValueType>();
            private Map<ValueType, KeyType> valueToKeyMap = new ConcurrentHashMap<ValueType, KeyType>();
    
            synchronized public void put(KeyType key, ValueType value){
                keyToValueMap.put(key, value);
                valueToKeyMap.put(value, key);
            }
    
            synchronized public ValueType removeByKey(KeyType key){
                ValueType removedValue = keyToValueMap.remove(key);
                valueToKeyMap.remove(removedValue);
                return removedValue;
            }
    
            synchronized public KeyType removeByValue(ValueType value){
                KeyType removedKey = valueToKeyMap.remove(value);
                keyToValueMap.remove(removedKey);
                return removedKey;
            }
    
            public boolean containsKey(KeyType key){
                return keyToValueMap.containsKey(key);
            }
    
            public boolean containsValue(ValueType value){
                return keyToValueMap.containsValue(value);
            }
    
            public KeyType getKey(ValueType value){
                return valueToKeyMap.get(value);
            }
    
            public ValueType get(KeyType key){
                return keyToValueMap.get(key);
            }
        }
    
        4
  •  11
  •   rsp    15 年前

    如果没有发生冲突,则可以将两个方向添加到同一个哈希图中:-)

        5
  •  3
  •   Fulvius    10 年前

    给我2美分。

    或者您可以对泛型使用一个简单的方法。小菜一碟。

    public static <K,V> Map<V, K> invertMap(Map<K, V> toInvert) {
        Map<V, K> result = new HashMap<V, K>();
        for(K k: toInvert.keySet()){
            result.put(toInvert.get(k), k);
        }
        return result;
    }
    

    当然,您必须有一个具有唯一值的映射。否则,其中一个将被替换。

        6
  •  0
  •   NekoKikoushi    9 年前

    这是一个很古老的问题,但是如果有人像我一样有大脑阻塞,并且偶然发现了这个问题,希望这能有所帮助。

    我也在寻找一个双向的哈希图,有时它是最简单的答案,是最有用的。

    如果您不希望重新发明控制盘,并且不希望向项目中添加其他库或项目,那么简单地实现并行数组(如果您的设计需要,可以使用arraylist)如何?

    SomeType[] keys1 = new SomeType[NUM_PAIRS];
    OtherType[] keys2 = new OtherType[NUM_PAIRS];
    

    只要你知道这两个键中1个的索引,你就可以轻松地请求另一个。因此,查找方法可能类似于:

    SomeType getKey1(OtherType ot);
    SomeType getKey1ByIndex(int key2Idx);
    OtherType getKey2(SomeType st); 
    OtherType getKey2ByIndex(int key2Idx);
    

    这是假设您使用的是适当的面向对象结构,其中只有方法在修改这些数组/数组列表时,保持它们平行是非常简单的。对于数组列表来说更容易,因为如果数组的大小发生变化,只要您连续添加/删除,就不必重新生成数组。

        7
  •  0
  •   Community Romance    7 年前

    灵感来自 GETah's answer 我决定自己写一些类似的东西,并做一些改进:

    • 该类正在实现 Map<K,V> -接口
    • 双向性的真正保证是在改变一个值时注意它 put (至少我希望在此保证)

    用法与普通映射类似,以获取映射调用的反向视图 getReverseView() . 不复制内容,只返回视图。

    我不确定这完全是一个傻瓜证明(事实上,这可能不是),所以如果你发现任何缺陷,请随时评论,我会更新答案。

    public class BidirectionalMap<Key, Value> implements Map<Key, Value> {
    
        private final Map<Key, Value> map;
        private final Map<Value, Key> revMap;
    
        public BidirectionalMap() {
            this(16, 0.75f);
        }
    
        public BidirectionalMap(int initialCapacity) {
            this(initialCapacity, 0.75f);
        }
    
        public BidirectionalMap(int initialCapacity, float loadFactor) {
            this.map = new HashMap<>(initialCapacity, loadFactor);
            this.revMap = new HashMap<>(initialCapacity, loadFactor);
        }
    
        private BidirectionalMap(Map<Key, Value> map, Map<Value, Key> reverseMap) {
            this.map = map;
            this.revMap = reverseMap;
        }
    
        @Override
        public void clear() {
            map.clear();
            revMap.clear();
        }
    
        @Override
        public boolean containsKey(Object key) {
            return map.containsKey(key);
        }
    
        @Override
        public boolean containsValue(Object value) {
            return revMap.containsKey(value);
        }
    
        @Override
        public Set<java.util.Map.Entry<Key, Value>> entrySet() {
            return Collections.unmodifiableSet(map.entrySet());
        }
    
        @Override
        public boolean isEmpty() {
            return map.isEmpty();
        }
    
        @Override
        public Set<Key> keySet() {
            return Collections.unmodifiableSet(map.keySet());
        }
    
        @Override
        public void putAll(Map<? extends Key, ? extends Value> m) {
            m.entrySet().forEach(e -> put(e.getKey(), e.getValue()));
        }
    
        @Override
        public int size() {
            return map.size();
        }
    
        @Override
        public Collection<Value> values() {
            return Collections.unmodifiableCollection(map.values());
        }
    
        @Override
        public Value get(Object key) {
            return map.get(key);
        }
    
        @Override
        public Value put(Key key, Value value) {
            Value v = remove(key);
            getReverseView().remove(value);
            map.put(key, value);
            revMap.put(value, key);
            return v;
        }
    
        public Map<Value, Key> getReverseView() {
            return new BidirectionalMap<>(revMap, map);
        }
    
        @Override
        public Value remove(Object key) {
            if (containsKey(key)) {
                Value v = map.remove(key);
                revMap.remove(v);
                return v;
            } else {
                return null;
            }
        }
    
    }
    
    推荐文章