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)按索引检索;它在内部实现为一个二元搜索树。因此,对LINQEnumerable.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);
我打赌调试输出比字典查找花费更多的时间