C# 提高SortedDictionary上的访问时间

C# 提高SortedDictionary上的访问时间,c#,.net,generics,.net-3.5,c#-3.0,C#,.net,Generics,.net 3.5,C# 3.0,我在一个SortedDictionary中有200万项 我做了以下几件事,花了很长时间,有什么想法吗 for(int i = 0; i<dic.Count-1; i++) { Debug.WriteLine(dic.ElementAt(i).Value.ToString()); } for(int i=0;iforeach可能更快,因为您不使用索引器 foreach (var value in dic.Values) Debug.Writeline(value) 此外,就

我在一个
SortedDictionary中有200万项

我做了以下几件事,花了很长时间,有什么想法吗

for(int i = 0; i<dic.Count-1; i++)
{
    Debug.WriteLine(dic.ElementAt(i).Value.ToString());
}

for(int i=0;i
foreach
可能更快,因为您不使用索引器

foreach (var value in dic.Values)
   Debug.Writeline(value)

此外,就速度而言,<>代码>调试.WordLe> 可能不是最好的选择(你将如何处理200万个调试跟踪条目?)。考虑写入文件、数据库等

编辑查看reflector,在SortedDictionary中查找值归结为二进制搜索:

internal virtual Node<T> FindNode(T item)
{
    int num;
    for (Node<T> node = this.root; node != null; node = (num < 0) ? node.Left : node.Right)
    {
        num = this.comparer.Compare(item, node.Item);
        if (num == 0)
        {
            return node;
        }
    }
    return null;
}
内部虚拟节点FindNode(T项)
{
int-num;
for(Node Node=this.root;Node!=null;Node=(num<0)?Node.Left:Node.Right)
{
num=this.comparer.Compare(item,node.item);
如果(num==0)
{
返回节点;
}
}
返回null;
}
SortedDictionary迭代的实现似乎更为复杂:

public bool MoveNext()
{
    this.tree.VersionCheck();
    if (this.version != this.tree.version)
    {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }
    if (this.stack.Count == 0)
    {
        this.current = null;
        return false;
    }
    this.current = this.stack.Pop();
    SortedSet<T>.Node item = this.reverse ? this.current.Left : this.current.Right;
    SortedSet<T>.Node node2 = null;
    SortedSet<T>.Node node3 = null;
    while (item != null)
    {
        node2 = this.reverse ? item.Right : item.Left;
        node3 = this.reverse ? item.Left : item.Right;
        if (this.tree.IsWithinRange(item.Item))
        {
            this.stack.Push(item);
            item = node2;
        }
        else
        {
            if ((node3 == null) || !this.tree.IsWithinRange(node3.Item))
            {
                item = node2;
                continue;
            }
            item = node3;
        }
    }
    return true;
}
public bool MoveNext()
{
this.tree.VersionCheck();
if(this.version!=this.tree.version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion除外);
}
if(this.stack.Count==0)
{
this.current=null;
返回false;
}
this.current=this.stack.Pop();
SortedSet.Node item=this.reverse?this.current.Left:this.current.Right;
SortedSet.node2=null;
SortedSet.node3=null;
while(项!=null)
{
node2=this.reverse?item.Right:item.Left;
node3=this.reverse?item.Left:item.Right;
if(此.tree.IsWithinRange(item.item))
{
本.栈.推(项);
项目=节点2;
}
其他的
{
if((node3==null)| |!this.tree.IsWithinRange(node3.Item))
{
项目=节点2;
继续;
}
项目=节点3;
}
}
返回true;
}
它似乎维护一个顶部元素最小(或最大,取决于方向)的堆栈一个,因此总是在迭代过程中弹出并返回一个。我没有做过任何复杂性分析,但它肯定比每次运行二进制搜索要高效得多。

该类不直接支持(fast)按索引检索;它在内部实现为一个二元搜索树。因此,对LINQ
Enumerable.ElementAt
方法的每次调用都会创建一个新的枚举器,该枚举器迭代集合中由键值对表示的序列的每个值(按键排序)从开始到达到所需的索引。这意味着循环必须在完成之前拉动类似
1+2+3+…+的元素计数(大约2万亿),使其时间复杂度(至少)为二次

请尝试此方法,该方法应大致以线性时间运行:

foreach(var myClass in dic.Values)
   Debug.WriteLine(myClass);

如果您真的希望通过索引快速访问(从提供的代码中,似乎没有任何理由表明这一点),请考虑使用A。

我也注意到循环条件是“代码> iDIC。计数-< 1 /代码>,而不是更常见的<代码> i> dic。计数< /COD>。这不是一个错误,或者您不打算考虑字典中的最后一个值。在后一种情况下,可以保持一个局部变量作为计数器,或者用LINQ:

foreach(var myClass in dic.Values.Take(dic.Count - 1))
   Debug.WriteLine(myClass);

使用foreach的

    foreach (var pair in d)
        Debug.WriteLine(pair.Value);
我打赌调试输出比字典查找花费更多的时间