独特的键值对集合

时间:2015-12-11 15:30:52

标签: c# .net collections big-o

是否有任何结构允许 BOTH 进行这些操作:

  • collection.TryGetValue(TKey, out TValue)
  • collection.TryGetKey(TValue, out TKey)

比O(n)更好的时间?

我的问题:

我基本上需要能够非常快速地检索键值值的键,而不会重复内存(所以两个词典都是毫无疑问)。

非常重要的说明:所有键都是唯一的,所有值都是唯一的。有了这些信息我感觉应该可以在更好的时间内完成这项任务,而不仅仅是.TryGetValue的O(1)和.TryGetKey的O(n)。

修改

就我而言,我在stringsints之间有一个映射。有大约650,000个键值对的文本及其ID。所以我基本上想要获取具有特定ID的字符串,以及某个字符串的ID。

3 个答案:

答案 0 :(得分:3)

要比O(n)更好,你需要使用第二本字典。但是正如您所提到的那样,您正在使用结构并且关注内存使用情况,第二个字典具有结构的副本。

解决此问题的一种方法是将对象内部的struct值框中,然后共享两个词典中的盒装对象。如果你使用DictionaryBase的继承,这实际上很容易实现。

public sealed class TwoWayDictionary<TKey, TValue> : DictionaryBase
{
    Hashtable reverseLookup = new Hashtable();

    public void Add(TKey key, TValue value)
    {
        this.Dictionary.Add(key, value);
    }

    public void Remove(TKey key)
    {
        this.Dictionary.Remove(key);
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        object lookup = Dictionary[key];
        if (lookup == null)
        {
            value = default(TValue);
            return false;
        }
        else
        {
            value = (TValue)lookup;
            return true;
        }
    }

    public bool TryGetKey(TValue value, out TKey key)
    {
        object lookup = reverseLookup[value];
        if (lookup == null)
        {
            key = default(TKey);
            return false;
        }
        else
        {
            key = (TKey)lookup;
            return true;
        }
    }

    //If OnInsertComplete or OnSetComplete raises a exception DictionaryBase will 
    // roll back the operation it completed.
    protected override void OnInsertComplete(object key, object value)
    {
        reverseLookup.Add(value, key);
    }

    protected override void OnSetComplete(object key, object oldValue, object newValue)
    {
        if(reverseLookup.Contains(newValue))
            throw new InvalidOperationException("Duplicate value");
        if(oldValue != null)
            reverseLookup.Remove(oldValue);
        reverseLookup[newValue] = key;
    }

    protected override void OnRemoveComplete(object key, object value)
    {
        reverseLookup.Remove(value);
    }
}

DictionaryreverseLookup词典将共享相同的引用,因此与使用两个带有大型结构的强类型词典相比,它的内存占用量更小。

如果没有编写一个完整的Dictionary<TKey, TValue>实现,它将两个内部存储桶集合用于键和值,而两个链接列表用于存储桶中的链,我认为您无法获得更好的结果。

答案 1 :(得分:0)

您可以为key编写一些包装器,其中包含value包装器的密钥和链接以及value的包装器,它应包含值并链接到key包装器。并使用两个不同的HashSet s 在这种情况下,您可以避免重复内存。您只需要额外的内存链接。

答案 2 :(得分:-2)

你可以做这样的事情;

Dictionary<string, string> types = new Dictionary<string, string>()
            {
                        {"1", "one"},
                        {"2", "two"},
                        {"3", "three"}
            };

            var myValue = types.FirstOrDefault(x => x.Value == "one").Key;