这个问题最初是错误的,请参阅下面的编辑。我会把它留给上下文。
我一直在考虑建立双向(即一对一)映射的智能方法。映射函数A-> B(多对一)基本上是HashMap(A,B)所做的。如果我现在想要一个与O(1)中的contains()实现一对一的数据结构,那么我可以使用java标准库中的某些东西吗?请注意,我现在不需要这个,这只是我最近想到的,无法提供数据结构,所以答案并不急。有类似的课吗?如果没有,您认为为什么会这样?
所有我能找到的就是关于冬眠的事情,这对我没有帮助。
编辑: 我的问题是措辞不好,所以应该作出一些解释。
我的意思是“向后”映射B-> A。 HashMap(A,B)在O(1)中包含(A)和包含(B),所以这甚至不是我的意思,对于混淆感到抱歉。我的意思是,是否有一个数据结构映射A< - > B在O(1)中有getValue(A)和getKey(B)?
我意识到这可以通过维护包含相同关系的两个HashMaps(A,B)和(B,A)来完成,但我觉得应该有一个数据结构可以处理它而不必这样做“手动”。
答案 0 :(得分:13)
我认为你不会比两个HashMaps做得更好。编写包装器界面非常简单:
class OneToOneMap<Key, Value> {
public void add(Key k, Value v) {
if (!keyToVal_.contains(k) && !valToKey_.contains(v)) {
keyToVal_.add(k, v);
valToKey_.add(v, k);
}
}
private HashMap<K, V> keyToVal_;
private HashMap<V, K> valToKey_;
}
我不确定这是否是有效的Java,但你明白了。
答案 1 :(得分:6)
我不知道现有的类为containsKey和containsValue执行O(1),但是你可以通过扩展HashMap来实现它,这样在插入时,你可以将每个值添加到内部HashSet。重载containsValue以对值HashSet进行查找。标准HashMap有O(1)containsKey,但O(n)containsValue。
同样,您可以在插入中强制执行1:1并检查现有值。
请注意,如果您遇到大量冲突,HashSet查找可能会在最坏的情况下达到O(n)。
答案 2 :(得分:4)
如果您愿意使用第三方库,Guava会为BiMap
提供一个很好的API。它提供getKey
视图,而不是inverse()
方法,返回BiMap<V, K>
。 (当然,它确实提供了恒定时间containsValue
。)
目前,HashBiMap
基本上内部有两个HashMap
保持同步 - 尽管它们如何保持它们彼此匹配非常一致 - 但实施可能会在未来变得更加智能
答案 3 :(得分:3)
我有同样的需求,想出了可能有用的BiMap。它只使用一个hashmap并返回一个条目对象,以便返回值可以被赋予特定类型,并允许映射为null。
public class BiMap<T1, T2>
{
public static class Entry<T1, T2>
{
public final T1 item1;
public final T2 item2;
public Entry( T1 item1, T2 item2 )
{
this.item1 = item1;
this.item2 = item2;
}
}
private final HashMap< Object, Entry<T1, T2> > mappings = new HashMap<>();
private int loopedLinkCount;
public void put( T1 item1, T2 item2 )
{
remove(item1);
remove(item2);
Entry<T1, T2> entry = new Entry<T1, T2>( item1, item2 );
mappings.put( item1, entry );
mappings.put( item2, entry );
if( Objects.equals(item1, item2) ){
loopedLinkCount++;
}
}
/**
*
* @param key
* @return an entry containing the key and it's one to one mapping or null if there is
* no mapping for the key.
*/
public Entry<T1, T2> get( Object key )
{
return mappings.get( key );
}
public Entry<T1, T2> remove( Object key )
{
Entry<T1, T2> entry = mappings.remove( key );
if( entry == null ){
return null;
}
if( Objects.equals( entry.item2, entry.item1 ) ){
loopedLinkCount--;
return entry;
}
return mappings.remove( Objects.equals( key, entry.item1 ) ? entry.item2 : entry.item1 );
}
public Set< Entry<T1, T2> > entrySet()
{
return new HashSet<>( mappings.values() );
}
public int size()
{
return ( mappings.size() + loopedLinkCount ) / 2;
}
}
答案 4 :(得分:2)
我最初的想法是使用标准地图,如果你有一个完美的哈希函数,你可以使用HashMap作为一对一的映射。如果我理解你在做什么,以下就足够了:
Map<String,Object> map = new HashMap<String,Object>();