【问题标题】:Java TreeMap with two keys and can work with single key?Java TreeMap 有两个键并且可以使用单个键?
【发布时间】:2020-03-30 19:38:01
【问题描述】:

我想要一个有两个键的 Treemap,可以单键调用。

示例:key1 是字符串,key2 是整数,值是对象。

数据示例:

{('alice', 124221, obj1), ('bob', 241241, obj2), .... }
getByString('alice') ==> obj1
getByInt(124221) ==> obj1

注意:永远不需要同时使用两个键来获取对象。一个就够了

问题:

可以在一张地图中实现吗?如果是,是否可以保证通过任一键获取值具有 O(log n) 时间复杂度?

【问题讨论】:

  • 两个键isn't a problem,但不同类型的键会受到伤害。您要么需要使用原始 TreeMap(只是不要),要么编写某种包装类。
  • 当然。如果你使用 HashMap,它甚至会是 O(1)。您只需将值输入两次:每个键一次。
  • @JBNizet 键的顺序很重要。那么,我想我应该只使用 TreeMap。
  • 啊,那么你需要两个映射,或者一个能够比较字符串和整数的比较器。
  • 两张地图是最好的办法。这个话题已经在here讨论过。

标签: java data-structures hashmap treemap


【解决方案1】:

正如@azurefrog 所指出的,您想要的行为不是由 TreeMap 直接提供的,因此您需要某种包装类。这是一个例子;我已经将 TreeMaps 用于内部实现,但除非你想以某种方式使用更多方法的排序,否则最好使用 HashMap 代替,因为那时你得到 O(1) 获取和放置操作,而不是 O(log n) .

import java.util.Map;
import java.util.TreeMap;

public class TwoKeysMap<K1 extends Comparable<K1>, K2 extends Comparable<K2>, V> {
    private static class Entry<K1 extends Comparable<K1>, K2 extends Comparable<K2>, V> {
        private final K1 k1;
        private final K2 k2;
        private final V v;

        private Entry(K1 k1, K2 k2, V v) {
            this.k1 = k1;
            this.k2 = k2;
            this.v = v;
        }
    }

    private final Map<K1, Entry<K1, K2, V>> map1 = new TreeMap<>();
    private final Map<K2, Entry<K1, K2, V>> map2 = new TreeMap<>();

    public V getByKey1(K1 k1) {
        Entry<K1, K2, V> e = map1.get(k1);
        return e != null ? e.v : null;
    }

    public V getByKey2(K2 k2) {
        Entry<K1, K2, V> e = map2.get(k2);
        return e != null ? e.v : null;
    }

    public void put(K1 k1, K2 k2, V v) {
        Entry<K1, K2, V> e = new Entry<>(k1, k2, v);
        map1.put(k1, e);
        map2.put(k2, e);
    }
}

用法:

> TwoKeysMap<String, Integer, Object> map = new TwoKeysMap<>();
> map.put("alice", 124221, "Object 1");
> map.put("bob", 241241, "Object 2");
> map.getByKey1("alice")
"Object 1" (Object)
> map.getByKey2(124221)
"Object 1" (Object)

请注意,内部Entry 类并非仅用于“get”和“put”,但如果您想通过 key1 删除,则条目也需要存储 key2,以便您可以从两个地图中删除,反之亦然:

    public void removeByKey1(K1 k1) {
        Entry<K1, K2, V> e = map1.remove(k1);
        if(e != null) {
            map2.remove(e.k2);
        }
    }

    public void removeByKey2(K2 k2) {
        Entry<K1, K2, V> e = map2.remove(k2);
        if(e != null) {
            map1.remove(e.k1);
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2018-08-14
    相关资源
    最近更新 更多