Java O(1)中的getKey(B)与一对一映射数据结构(A,B)?

Java O(1)中的getKey(B)与一对一映射数据结构(A,B)?,java,contains,one-to-one,Java,Contains,One To One,这个问题最初措辞错误,请参见下面的编辑。我将留待上下文讨论 我一直在思考构建双射(即一对一)映射的智能方法。映射函数a->B(多对一)基本上就是HashMap(a,B)所做的。如果我现在想要一个数据结构,在O(1)中实现一对一的contains(),那么java标准库中是否有我可以使用的东西?请注意,我现在什么都不需要这个,这只是我最近考虑过的事情,无法为它提供数据结构,所以答案并不仓促。有这样的课吗?如果没有,你认为这是什么原因 我能找到的只有关于hibernate的东西,这对我毫无帮助 编辑

这个问题最初措辞错误,请参见下面的编辑。我将留待上下文讨论

我一直在思考构建双射(即一对一)映射的智能方法。映射函数a->B(多对一)基本上就是HashMap(a,B)所做的。如果我现在想要一个数据结构,在O(1)中实现一对一的contains(),那么java标准库中是否有我可以使用的东西?请注意,我现在什么都不需要这个,这只是我最近考虑过的事情,无法为它提供数据结构,所以答案并不仓促。有这样的课吗?如果没有,你认为这是什么原因

我能找到的只有关于hibernate的东西,这对我毫无帮助

编辑: 我的问题措词不当,因此需要作一些解释

我的意思是“向后”映射B->A。HashMap(A,B)在O(1)中包含(A)和(B),所以这甚至不是我的意思,很抱歉混淆了。我的意思是,是否有一个数据结构映射AB,在O(1)中有getValue(a)和getKey(B)


我意识到这可以通过两个HashMap(A,B)和(B,A)来实现,它们被维护为包含相同的关系,但我觉得应该有一个数据结构来处理它,而不必“手动”进行处理,如果你有一个完美的散列函数,你可以使用散列映射作为一对一的映射。如果我了解你在做什么,以下内容就足够了:

Map<String,Object> map = new HashMap<String,Object>();  
Map Map=newhashmap();

我不知道现有的类对containsKey和containsValue都执行O(1)操作,但是您可以通过扩展HashMap来完成,这样在插入时,您可以将每个值添加到内部HashSet中。重载containsValue以查找HashSet中的值。标准HashMap有O(1)containsKey,但O(n)containsValue

同样,可以在insert中强制执行1:1并检查现有值


请注意,如果发生大量冲突,最坏的情况下,哈希集查找可以达到O(n)。

我认为您不会比两个哈希映射做得更好。编写包装器接口非常简单:

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_;
}
class-OneToOneMap{
公共无效添加(键k,值v){
如果(!keyToVal_uu.contains(k)&&!valToKey_uu.contains(v)){
keyToVal添加(k,v);
瓦尔托克伊加(v,k);
}
}
私有HashMap keyToVal;
私有HashMap valToKey_;
}

我不确定这是否是有效的Java,但你明白了。

如果你愿意使用第三方库,Guava也提供了一个很好的API。它不是一个
getKey
方法,而是提供一个
inverse()
视图,返回一个
BiMap
。(当然,它确实提供了恒定的时间
containsValue


目前,
HashBiMap
基本上是内部两个保持同步的
HashMap
——尽管它在如何保持它们之间的匹配方面非常一致——但实现在未来可能会变得更智能。

我也有同样的需求,并提出了这个可能有用的BiMap。它只使用一个hashmap并返回一个entry对象,这样可以为返回值指定一个特定的类型,并允许映射为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;
    }
}
公共类BiMap
{
公共静态类条目
{
公共最终T1项目1;
公共最终项目2;
公共入口(T1项目1、T2项目2)
{
这个项目1=项目1;
本条第2项=第2项;
}
}
私有最终HashMapmappings=newhashmap();
私有int-loopedLinkCount;
公开作废认沽权证(T1第1项、T2第2项)
{
删除(第1项);
删除(第2项);
条目=新条目(条目1、条目2);
put(item1,entry);
映射.put(第2项,条目);
if(Objects.equals(item1,item2)){
loopedLinkCount++;
}
}
/**
* 
*@param-key
*@返回一个包含密钥的条目,该条目为一对一映射,如果存在,则返回null
*没有键的映射。
*/
公共条目获取(对象密钥)
{
返回映射。get(键);
}
删除公共条目(对象密钥)
{
条目=映射。删除(键);
if(条目==null){
返回null;
}
if(Objects.equals(entry.item2,entry.item1)){
循环链接计数--;
返回条目;
}
返回映射.remove(Objects.equals(key,entry.item1)?entry.item2:entry.item1);
}
公共集entrySet()
{
返回新的HashSet(mappings.values());
}
公共整数大小()
{
返回(mappings.size()+loopedLinkCount)/2;
}
}

是否只需扩展类A并添加一个返回B的属性就可以了?那么,如果HashMap不这样做,您想要什么呢?它可以用于一对一映射。@PeterLawrey是java O(1)中的HashMap.contains?您是否在寻找一对一映射上的约束,因为HashMap可以用于一对一映射,并且有一个选择充分的哈希函数和一个足够小的集合,在摊销O(1)中有contains.我才意识到我的问题并不能真正表达我的愿望;编辑。这不限于1对1的映射。许多键可以具有相同的值。编辑:我错了…@BlackPlanet不正确。如果你仔细阅读我的回答,我说的是完美的散列函数,对不起。我读得不够仔细。你完全正确+1因为它回答了我最初的问题,正如我意识到的那样,这个问题的措辞并不是我真正想问的。但是是的,一个完美的散列函数可以保证键和值之间的一对一关系,谢谢!可以肯定的是,两个HashMap将满足O(1)访问的要求,一个是映射A->B,另一个是映射B->A