C# 快速查找SortedDictionary中第一个未使用的键的方法?
如果我有一个C# 快速查找SortedDictionary中第一个未使用的键的方法?,c#,.net,key,sorteddictionary,C#,.net,Key,Sorteddictionary,如果我有一个SortedDictionary,找到当前未使用的最低键的最快方法是什么?显然,我们可以从0->int.MaxValue迭代计数器i,并在时转义!Keys.Contains(i),但这将非常缓慢,除非我们运气好,并且第一个备用密钥恰好在密钥序列的早期。也许甚至一个不同的.NET类已经在为我们做这件事了?我并没有因为这种方法而要求任何形式的性能奖杯,但我认为它在某种程度上有助于实现您的目标: var sd = new SortedDictionary<int, object>
SortedDictionary
,找到当前未使用的最低键的最快方法是什么?显然,我们可以从0->int.MaxValue
迭代计数器i,并在时转义!Keys.Contains(i)
,但这将非常缓慢,除非我们运气好,并且第一个备用密钥恰好在密钥序列的早期。也许甚至一个不同的.NET类已经在为我们做这件事了?我并没有因为这种方法而要求任何形式的性能奖杯,但我认为它在某种程度上有助于实现您的目标:
var sd = new SortedDictionary<int, object>();
sd.Add(1, 1);
sd.Add(2, 1);
sd.Add(4, 1);
sd.Add(5, 1);
var e = Enumerable.Range(1, 5).Except(sd.Keys).First();
var sd=new SortedDictionary();
sd.添加(1,1);
sd.添加(2,1);
sd.添加(4,1);
sd.添加(5,1);
var e=可枚举的.Range(1,5).Except(sd.Keys).First();
在这种情况下,e=3,如预期。不过,我希望有更好的解决方案。因此,如果我理解正确,键可以在
0
到int.MaxValue
之间的任意位置。在这种情况下,您必须找到键序列中的第一个“孔”
这将有效地完成工作:
public static int GetFirstUnusedKey<TValue>(SortedDictionary<int, TValue> dict)
{
if (dict.Comparer != Comparer<int>.Default)
throw new NotSupportedException("Unsupported comparer");
using (var enumerator = dict.GetEnumerator())
{
if (!enumerator.MoveNext())
return 0;
var nextKeyInSequence = enumerator.Current.Key + 1;
if (nextKeyInSequence < 1)
throw new InvalidOperationException("The dictionary contains keys less than 0");
if (nextKeyInSequence != 1)
return 0;
while (enumerator.MoveNext())
{
var key = enumerator.Current.Key;
if (key > nextKeyInSequence)
return nextKeyInSequence;
++nextKeyInSequence;
}
return nextKeyInSequence;
}
}
public static int GetFirstUnusedKey(SortedDictionary dict)
{
if(dict.Comparer!=Comparer.Default)
抛出新的NotSupportedException(“不支持的比较器”);
使用(var枚举器=dict.GetEnumerator())
{
如果(!enumerator.MoveNext())
返回0;
var nextKeyInSequence=enumerator.Current.Key+1;
if(nextKeyInSequence<1)
抛出新的InvalidOperationException(“字典包含小于0的键”);
if(nextKeyInSequence!=1)
返回0;
while(枚举数.MoveNext())
{
var key=enumerator.Current.key;
如果(键>下一个键序列)
返回nextKeyInSequence;
++nextKeyInSequence;
}
返回nextKeyInSequence;
}
}
我添加了一些检查以确保前提条件有效。不要搜索从0开始的未使用密钥 相反,迭代使用的键,从最低点开始(它们已排序) 第一个值大于0,然后0是最低未使用值
或者两个键之间有间隙,那么搜索的是lower+1。为什么不对键进行二进制搜索
可以使用ElementAt()方法标识索引处的键值。如果键值大于索引,则在左侧子字典中搜索,或选择右侧子字典并继续搜索,直到找到索引,在该索引处您观察到索引和索引处的值之间的第一个差异 你知道你字典里可能有多少人吗?可能会有多少把钥匙?当然-事实上,我很乐意按照我建议的笨重的方式去做,或者确实会跟踪备用钥匙,因为我不太可能有庞大的字典,但聪明的方式会很好:)很好。我想那会很有效率的。我相信用一本小字典就可以了。我不知道它将如何扩展。我猜这是卢卡斯答案的散文版;)Lol.DrKoch-当然可以,但对于几乎“满”的大型词典来说仍然是个问题。当主键溢出时,数据库会做什么?如果您经常这样做,您可以维护一个变量“LastGapFoundAtKey”,并在下次从该变量开始。数据库首先不会使用
SortedDictionary
)如果你的字典很满,你应该使用不同的数据结构。这种情况不会经常发生,所以事实上任何方法都可以,但我只是想知道是否有一种聪明的O(logn)或更好的方法ElementAt
将在每次调用@DrKoch时枚举字典。这使得此解决方案更像O(n²)。如果SortedDictionary
实现IList
.Hmmm,它将起作用。很好@Lucas,但是如果我们查找的键从intmax/2开始,然后向左搜索,如果左半部分已满,可能再向右搜索,那么二进制搜索可能会有所帮助。@Rob这里的问题是类SortedDictionary.KeyCollection
没有实现IList
,只有ICollection
而且没有索引。@科赫博士,我可以这样做,但那样我就失去了使用字典的好处。我的应用程序需要a)使用一个不变的键跟踪对象,b)能够快速地通过其键检索对象。密钥溢出问题不太可能发生,但需要注意,以防万一