检查存在然后插入SortedList的快速方法

时间:2012-11-08 16:11:14

标签: c# performance sortedlist

每当我想插入SortedList时,我会检查项目是否存在,然后插入。这两次执行相同的搜索吗?一旦看到该项目是否存在并再次找到插入项目的位置?有没有办法优化它以加快速度,或者这只是这样做的方式,不需要进行任何更改吗?

if( sortedList.ContainsKey( foo ) == false ){
    sortedList.Add( foo, 0 );
}

5 个答案:

答案 0 :(得分:6)

您可以将项添加到HashSet和List中,在哈希集中搜索是查看是否必须将值添加到列表的最快方法。

if( hashSet.Contains( foo ) == false ){
    sortedList.Add( foo, 0 );  
    hashSet.Add(foo);
}

答案 1 :(得分:1)

您可以使用索引器。索引器在内部以最佳方式执行此操作,首先使用二进制搜索查找与键对应的索引,然后使用此索引替换现有项。否则,通过考虑已经计算的索引来添加新项目。

list["foo"] = value;

无论密钥是否已存在,都不会抛出任何异常。


<强>更新

如果新值与旧值相同,则替换旧值将具有与不执行任何操作相同的效果。

请记住二进制搜索已完成。这意味着在1000个项目中找到一个项目大约需要10个步骤! log2(1000) ~= 10。因此,进行额外搜索不会对速度产生重大影响。在1,000,000个项目中搜索只会使这个值加倍(约20步)。

但是,通过索引器设置值在任何情况下都只会进行一次搜索。我使用Reflector查看了代码,可以确认这一点。

答案 2 :(得分:1)

如果这不能回答你的问题,我很抱歉,但我不得不说,有时.NET中的默认收集结构在功能上是不合理的。如果Add方法返回一个表示成功/失败的布尔值,就像HashSet<T>.Add那样,可以处理这个问题。所以一切都在一步之中。实际上整个ICollection<T>.Add应该是一个布尔值,因此强制实现它,就像Java中的Collection<T>一样。

您可以使用Servy指出的SortedDictionary<K, V>结构,或HashSet<K>SortedList<K, V>的组合,如peer's answer更好性能,但他们都没有真正坚持只做一次哲学。我尝试了几个开源项目,看看在这方面是否有更好的实现,但找不到。

您的选择:

  1. 在绝大多数情况下,可以进行两次查找,但不会造成太大影响。坚持一个。没有内置解决方案。

  2. 编写自己的SortedList<K, V>课程。这根本不难。

  3. 如果你绝望,你可以使用反射。 Insert方法是SortedList类中的私有成员。 An example that does.。请不要这样做。这是一个非常糟糕的选择。这里提到完整性。

答案 3 :(得分:0)

ContainsKey进行二进制搜索,即O(log n),所以除非你列出的是大量的,否则我不会太担心它。并且,据推测,在插入时,它会执行另一个二进制搜索以找到要插入的位置。

避免这种情况的一个选项(进行两次搜索)是使用List的BinarySearch方法。如果找不到该项,则返回负值,负值是应插入项的位置的按位补码。所以你可以查找一个项目,如果它不在列表中,你就知道应该在哪里插入它以保持列表的排序。

答案 4 :(得分:0)

SortedList<Key,Value>是一种缓慢的数据结构,您可能根本不应该使用它。您可能已经考虑使用SortedDictionary<Key,Value>,但发现它不方便,因为这些项目没有索引(您不能写sortedDictionary[0]),因为您可以写find nearest key SortedList但不是SortedDictionary的操作。

但是,如果您愿意切换到第三方库,则可以通过更改为不同的数据结构来获得更好的性能。

Loyc Core库包含的数据类型与SortedList<Key,Value>的工作方式相同,但在列表较大时速度要快得多。它被称为BDictionary<Key,Value>

现在,回答你的原始问题:是的,你编写代码的方式,它执行两次搜索和一次插入(插入是最慢的部分)。如果切换到BDictionary,则会有一个方法bdictionary.AddIfNotPresent(key, value)将这两个操作合并为一个操作。如果添加了指定的项,则返回true;如果已经存在,则返回false。