简体   繁体   English

在TreeMap中搜索(Java)

[英]Searching in a TreeMap (Java)

I need to do a search in a map of maps and return the keys this element belong. 我需要在地图地图中进行搜索,然后返回该元素所属的键。 I think this implementation is very slow, can you help me to optimize it?. 我认为此实现非常慢,您可以帮助我对其进行优化吗? I need to use TreeSet and I can't use contains because they use compareTo, and equals/compareTo pair are implemented in an incompatible way and I can't change that. 我需要使用TreeSet,而不能使用contains,因为它们使用compareTo,并且equals / compareTo对以不兼容的方式实现,我无法更改。 (sorry my bad english) (对不起,我的英语不好)

Map<Key, Map<SubKey, Set<Element>>> m = new TreeSet();

public String getKeys(Element element) { 
 for(Entry<Key, Map<SubKey, Set<Element>>> e : m.entrySet()) {
  mapSubKey = e.getValue();
  for(Entry<SubKey, Set<Element>> e2 : mapSubKey.entrySet()) {
   setElements = e2.getValue();
   for(Element elem : setElements)
    if(elem.equals(element)) return "Key: " + e.getKey() + " SubKey: " + e2.getKey();
  }
 }
}

The problem here is that the keys and values are backward. 这里的问题是键和值是向后的。

Maps allow one to efficiently find a value (which would be Key and SubKey ) associated with a key ( Element , in this example). 映射允许人们有效地找到与键(在此示例中为Element )关联的值(该Key将为KeySubKey )。

Going backwards is slow. 向后退是很慢的。

There are bi-directional map implementations, like Google Collections BiMap, that support faster access in both directions—but that would mean replacing TreeMap . 有双向地图实现(例如Google Collections BiMap)支持双向的更快访问,但这意味着要替换TreeMap Otherwise, maintain two maps, one for each direction. 否则,请维护两张地图,每个方向一张。

if you can't use contains , and you're stuck using a Map of Maps, then your only real option is to iterate, as you are doing. 如果您不能使用contains ,并且无法使用Map of Map,那么您唯一的选择就是进行迭代。

alternatively, you could keep a reverse map of Element to Key/SubKey in a separate map, which would make reverse lookups faster. 或者,您可以将ElementKey/SubKey的反向映射保留在单独的映射中,这将使反向查找更快。

also, if you're not sure that a given Element can exist in only one place, you might want to store and retrieve a List<Element> instead of just an Element 另外,如果不确定给定的Element只能存在于一个位置,则可能要存储和检索List<Element>而不只是一个Element

Using TreeMap and TreeSet work properly when compareTo and equals are implemented in such a way that they are compatible with each other. 当执行compareToequals相互兼容的方式时,使用TreeMapTreeSet可以正常工作。 Furthermore, when searching in a Map, only the search for the key will be efficient (for a TreeMap O(log n)). 此外,在地图中进行搜索时,仅对键的搜索将非常有效(对于TreeMap O(log n))。 When searching for a value in a Map, the complexity will become linear. 在地图中搜索值时,复杂度将变为线性。

There is a way to optimize the search in the inner TreeSet though, when implementing your own Comparator for the Element type. 但是,当为Element类型实现自己的Comparator时,有一种方法可以优化内部TreeSet中的搜索。 This way you can implement your own compareTo method without changing the Element object itself. 这样,您可以实现自己的compareTo方法,而无需更改Element对象本身。

Here is a bidirectional TreeMap (or Bijection over TreeMap). 这是双向TreeMap(或TreeMap上的Bijection)。

It associates two overloaded TreeMaps Which are tied together. 它将两个重载的TreeMap关联在一起。

Each one "inverse" constant field points to the other TreeMap. 每个“反向”常量字段都指向另一个TreeMap。 Any change on one TreeMap is automatically reflected on its inverse. 一个TreeMap上的任何更改都会自动反映在其逆向上。

As a result, each value is unique. 结果,每个值都是唯一的。

public class BiTreeMap<K, V> extends TreeMap<K, V> {
    public final BiTreeMap<V, K> inverse;

    private BiTreeMap(BiTreeMap inverse) {
        this.inverse = inverse;
    }

    public BiTreeMap() {
        inverse = new BiTreeMap<V, K>(this);
    }

    public BiTreeMap(Map<? extends K, ? extends V> m) {
        inverse = new BiTreeMap<V, K>(this);
        putAll(m);
    }

    public BiTreeMap(Comparator<? super K> comparator) {
        super(comparator);
        inverse = new BiTreeMap<V, K>(this);
    }

    public BiTreeMap(Comparator<? super K> comparatorK, Comparator<? super V> comparatorV) {
        super(comparatorK);
        inverse = new BiTreeMap<V, K>(this, comparatorV);
    }

    private BiTreeMap(BiTreeMap<V, K> inverse, Comparator<? super K> comparatorK) {
        super(comparatorK);
        this.inverse = inverse;
    }

    @Override
    public V put(K key, V value) {
        if(key == null || value == null) {
            throw new NullPointerException();
        }
        V oldValue = super.put(key, value);
        if (oldValue != null && inverse._compareKeys(value, oldValue) != 0) {
            inverse._remove(oldValue);
        }
        K inverseOldKey = inverse._put(value, key);
        if (inverseOldKey != null && _compareKeys(key, inverseOldKey) != 0) {
            super.remove(inverseOldKey);
        }
        return oldValue;
    }

    private int _compareKeys(K k1, K k2) {
        Comparator<? super K> c = comparator();
        if (c == null) {
            Comparable<? super K> ck1 = (Comparable<? super K>) k1;
            return ck1.compareTo(k2);
        } else {
            return c.compare(k1, k2);
        }
    }

    private V _put(K key, V value) {
        return super.put(key, value);
    }

    @Override
    public V remove(Object key) {
        V value = super.remove(key);
        inverse._remove(value);
        return value;
    }

    private V _remove(Object key) {
        return super.remove(key);
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map) {
        for (Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
            K key = e.getKey();
            V value = e.getValue();
            put(key, value);
        }
    }

    @Override
    public void clear() {
        super.clear();
        inverse._clear();
    }

    private void _clear() {
        super.clear();
    }

    public boolean containsValue(Object value) {
        return inverse.containsKey(value);
    }

    @Override
    public Map.Entry<K, V> pollFirstEntry() {
        Map.Entry<K, V> entry = super.pollFirstEntry();
        inverse._remove(entry.getValue());
        return entry;
    }

    @Override
    public Map.Entry<K, V> pollLastEntry() {
        Map.Entry<K, V> entry = super.pollLastEntry();
        inverse._remove(entry.getValue());
        return entry;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM