📄 treebidimap.java
字号:
/*
* Copyright 2001-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.bidimap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.KeyValue;
import org.apache.commons.collections.MapIterator;
import org.apache.commons.collections.OrderedBidiMap;
import org.apache.commons.collections.OrderedIterator;
import org.apache.commons.collections.OrderedMapIterator;
import org.apache.commons.collections.iterators.EmptyOrderedMapIterator;
import org.apache.commons.collections.keyvalue.UnmodifiableMapEntry;
/**
* Red-Black tree-based implementation of BidiMap where all objects added
* implement the <code>Comparable</code> interface.
* <p>
* This class guarantees that the map will be in both ascending key order
* and ascending value order, sorted according to the natural order for
* the key's and value's classes.
* <p>
* This Map is intended for applications that need to be able to look
* up a key-value pairing by either key or value, and need to do so
* with equal efficiency.
* <p>
* While that goal could be accomplished by taking a pair of TreeMaps
* and redirecting requests to the appropriate TreeMap (e.g.,
* containsKey would be directed to the TreeMap that maps values to
* keys, containsValue would be directed to the TreeMap that maps keys
* to values), there are problems with that implementation.
* If the data contained in the TreeMaps is large, the cost of redundant
* storage becomes significant. The {@link DualTreeBidiMap} and
* {@link DualHashBidiMap} implementations use this approach.
* <p>
* This solution keeps minimizes the data storage by holding data only once.
* The red-black algorithm is based on java util TreeMap, but has been modified
* to simultaneously map a tree node by key and by value. This doubles the
* cost of put operations (but so does using two TreeMaps), and nearly doubles
* the cost of remove operations (there is a savings in that the lookup of the
* node to be removed only has to be performed once). And since only one node
* contains the key and value, storage is significantly less than that
* required by two TreeMaps.
* <p>
* The Map.Entry instances returned by the appropriate methods will
* not allow setValue() and will throw an
* UnsupportedOperationException on attempts to call that method.
*
* @since Commons Collections 3.0 (previously DoubleOrderedMap v2.0)
* @version $Revision: 1.14 $ $Date: 2004/05/26 21:58:02 $
*
* @author Marc Johnson
* @author Stephen Colebourne
*/
public class TreeBidiMap implements OrderedBidiMap {
private static final int KEY = 0;
private static final int VALUE = 1;
private static final int MAPENTRY = 2;
private static final int INVERSEMAPENTRY = 3;
private static final int SUM_OF_INDICES = KEY + VALUE;
private static final int FIRST_INDEX = 0;
private static final int NUMBER_OF_INDICES = 2;
private static final String[] dataName = new String[] { "key", "value" };
private Node[] rootNode = new Node[2];
private int nodeCount = 0;
private int modifications = 0;
private Set keySet;
private Set valuesSet;
private Set entrySet;
private TreeBidiMap.Inverse inverse = null;
//-----------------------------------------------------------------------
/**
* Constructs a new empty TreeBidiMap.
*/
public TreeBidiMap() {
super();
}
/**
* Constructs a new TreeBidiMap by copying an existing Map.
*
* @param map the map to copy
* @throws ClassCastException if the keys/values in the map are
* not Comparable or are not mutually comparable
* @throws NullPointerException if any key or value in the map is null
*/
public TreeBidiMap(final Map map) {
super();
putAll(map);
}
//-----------------------------------------------------------------------
/**
* Returns the number of key-value mappings in this map.
*
* @return the number of key-value mappings in this map
*/
public int size() {
return nodeCount;
}
/**
* Checks whether the map is empty or not.
*
* @return true if the map is empty
*/
public boolean isEmpty() {
return (nodeCount == 0);
}
/**
* Checks whether this map contains the a mapping for the specified key.
* <p>
* The key must implement <code>Comparable</code>.
*
* @param key key whose presence in this map is to be tested
* @return true if this map contains a mapping for the specified key
* @throws ClassCastException if the key is of an inappropriate type
* @throws NullPointerException if the key is null
*/
public boolean containsKey(final Object key) {
checkKey(key);
return (lookup((Comparable) key, KEY) != null);
}
/**
* Checks whether this map contains the a mapping for the specified value.
* <p>
* The value must implement <code>Comparable</code>.
*
* @param value value whose presence in this map is to be tested
* @return true if this map contains a mapping for the specified value
* @throws ClassCastException if the value is of an inappropriate type
* @throws NullPointerException if the value is null
*/
public boolean containsValue(final Object value) {
checkValue(value);
return (lookup((Comparable) value, VALUE) != null);
}
/**
* Gets the value to which this map maps the specified key.
* Returns null if the map contains no mapping for this key.
* <p>
* The key must implement <code>Comparable</code>.
*
* @param key key whose associated value is to be returned
* @return the value to which this map maps the specified key,
* or null if the map contains no mapping for this key
* @throws ClassCastException if the key is of an inappropriate type
* @throws NullPointerException if the key is null
*/
public Object get(final Object key) {
return doGet((Comparable) key, KEY);
}
/**
* Puts the key-value pair into the map, replacing any previous pair.
* <p>
* When adding a key-value pair, the value may already exist in the map
* against a different key. That mapping is removed, to ensure that the
* value only occurs once in the inverse map.
* <pre>
* BidiMap map1 = new TreeBidiMap();
* map.put("A","B"); // contains A mapped to B, as per Map
* map.put("A","C"); // contains A mapped to C, as per Map
*
* BidiMap map2 = new TreeBidiMap();
* map.put("A","B"); // contains A mapped to B, as per Map
* map.put("C","B"); // contains C mapped to B, key A is removed
* </pre>
* <p>
* Both key and value must implement <code>Comparable</code>.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value for the key
* @throws ClassCastException if the key is of an inappropriate type
* @throws NullPointerException if the key is null
*/
public Object put(final Object key, final Object value) {
return doPut((Comparable) key, (Comparable) value, KEY);
}
/**
* Puts all the mappings from the specified map into this map.
* <p>
* All keys and values must implement <code>Comparable</code>.
*
* @param map the map to copy from
*/
public void putAll(Map map) {
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
put(entry.getKey(), entry.getValue());
}
}
/**
* Removes the mapping for this key from this map if present.
* <p>
* The key must implement <code>Comparable</code>.
*
* @param key key whose mapping is to be removed from the map.
* @return previous value associated with specified key,
* or null if there was no mapping for key.
* @throws ClassCastException if the key is of an inappropriate type
* @throws NullPointerException if the key is null
*/
public Object remove(final Object key) {
return doRemove((Comparable) key, KEY);
}
/**
* Removes all mappings from this map.
*/
public void clear() {
modify();
nodeCount = 0;
rootNode[KEY] = null;
rootNode[VALUE] = null;
}
//-----------------------------------------------------------------------
/**
* Returns the key to which this map maps the specified value.
* Returns null if the map contains no mapping for this value.
* <p>
* The value must implement <code>Comparable</code>.
*
* @param value value whose associated key is to be returned.
* @return the key to which this map maps the specified value,
* or null if the map contains no mapping for this value.
* @throws ClassCastException if the value is of an inappropriate type
* @throws NullPointerException if the value is null
*/
public Object getKey(final Object value) {
return doGet((Comparable) value, VALUE);
}
/**
* Removes the mapping for this value from this map if present.
* <p>
* The value must implement <code>Comparable</code>.
*
* @param value value whose mapping is to be removed from the map
* @return previous key associated with specified value,
* or null if there was no mapping for value.
* @throws ClassCastException if the value is of an inappropriate type
* @throws NullPointerException if the value is null
*/
public Object removeValue(final Object value) {
return doRemove((Comparable) value, VALUE);
}
//-----------------------------------------------------------------------
/**
* Gets the first (lowest) key currently in this map.
*
* @return the first (lowest) key currently in this sorted map
* @throws NoSuchElementException if this map is empty
*/
public Object firstKey() {
if (nodeCount == 0) {
throw new NoSuchElementException("Map is empty");
}
return leastNode(rootNode[KEY], KEY).getKey();
}
/**
* Gets the last (highest) key currently in this map.
*
* @return the last (highest) key currently in this sorted map
* @throws NoSuchElementException if this map is empty
*/
public Object lastKey() {
if (nodeCount == 0) {
throw new NoSuchElementException("Map is empty");
}
return greatestNode(rootNode[KEY], KEY).getKey();
}
/**
* Gets the next key after the one specified.
* <p>
* The key must implement <code>Comparable</code>.
*
* @param key the key to search for next from
* @return the next key, null if no match or at end
*/
public Object nextKey(Object key) {
checkKey(key);
Node node = nextGreater(lookup((Comparable) key, KEY), KEY);
return (node == null ? null : node.getKey());
}
/**
* Gets the previous key before the one specified.
* <p>
* The key must implement <code>Comparable</code>.
*
* @param key the key to search for previous from
* @return the previous key, null if no match or at start
*/
public Object previousKey(Object key) {
checkKey(key);
Node node = nextSmaller(lookup((Comparable) key, KEY), KEY);
return (node == null ? null : node.getKey());
}
//-----------------------------------------------------------------------
/**
* Returns a set view of the keys contained in this map in key order.
* <p>
* The set is backed by the map, so changes to the map are reflected in
* the set, and vice-versa. If the map is modified while an iteration over
* the set is in progress, the results of the iteration are undefined.
* <p>
* The set supports element removal, which removes the corresponding mapping
* from the map. It does not support the add or addAll operations.
*
* @return a set view of the keys contained in this map.
*/
public Set keySet() {
if (keySet == null) {
keySet = new View(this, KEY, KEY);
}
return keySet;
}
//-----------------------------------------------------------------------
/**
* Returns a set view of the values contained in this map in key order.
* The returned object can be cast to a Set.
* <p>
* The set is backed by the map, so changes to the map are reflected in
* the set, and vice-versa. If the map is modified while an iteration over
* the set is in progress, the results of the iteration are undefined.
* <p>
* The set supports element removal, which removes the corresponding mapping
* from the map. It does not support the add or addAll operations.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -