目前我使用Dictionary<int,node>
来存储大约10,000个节点。密钥用作ID号以便以后查找,“node”是包含一些数据的类。程序中的其他类使用ID号作为指向节点的指针。 (这可能听起来效率低下。但是,解释我为此使用字典的原因超出了我的问题的范围。)
但是,20%的节点是重复的。 我想要做的是当我添加节点检查以查看是否所有准备就绪。如果是,则使用该ID号。如果没有创建一个新的。
这是我目前解决问题的方法:
public class nodeDictionary
{
Dictionary<int, node> dict = new Dictionary<int, node>( );
public int addNewNode( latLng ll )
{
node n = new node( ll );
if ( dict.ContainsValue( n ) )
{
foreach ( KeyValuePair<int, node> kv in dict )
{
if ( kv.Value == n )
{
return kv.Key;
}
}
}
else
{
if ( dict.Count != 0 )
{
dict.Add( dict.Last( ).Key + 1, n );
return dict.Last( ).Key + 1;
}
else
{
dict.Add( 0, n );
return 0;
}
}
throw new Exception( );
}//end add new node
}
这个问题是当尝试将新节点添加到100,000个节点的列表时,添加节点需要78毫秒。这是不可接受的,因为我可以在任何给定时间添加额外的1,000个节点。
那么,有没有更好的方法呢?我不是在找人为我编写代码,我只是在寻找指导。
答案 0 :(得分:3)
听起来你想要
IEquatable<LatLng>
接口)HashSet<LatLng>
有关实施GetHashCode的信息,请参阅此处:Why is it important to override GetHashCode when Equals method is overridden?
如果您需要以某种方式生成“人工”唯一ID,我建议您再次使用字典方法,但“反向”:
// uses the same hash function for speedy lookup/insertion
IDictionary<LatLng, int> idMap = new Dictionary<LatLng, int>();
foreach (LatLng latLng in LatLngCoords)
{
if (!idMap.ContainsKey(latLng))
idMap.Add(latLng, idMap.Count+1); // to start with 1
}
您可以让idMap
替换HashSet<>
;实现(和性能特征)基本相同,但作为关联容器。
这是一个从LatLng到Id的查找函数:
int IdLookup(LatLng latLng)
{
int id;
if (idMap.TryGetValue(latLng, id))
return id;
throw new InvalidArgumentException("Coordinate not in idMap");
}
你可以及时添加它:
int IdFor(LatLng latLng)
{
int id;
if (idMap.TryGetValue(latLng, id))
return id;
id = idMap.Count+1;
idMap.Add(latLng, id);
return id;
}
答案 1 :(得分:1)
此代码的目的究竟是什么?
if ( dict.ContainsValue( n ) )
{
foreach ( KeyValuePair kv in dict )
{
if ( kv.Value == n )
{
return kv.Key;
}
}
}
ContainsValue
搜索值(而不是键)并且效率非常低(O(n))。同上foreach
。更不用说只有一个是必要的时候才能同时执行这两项操作(您可以通过重新排列ContainsValue
s来完全删除if
!
你应该维护一个与原始字典“反向”的附加字典(即旧字典中的值是新字典中的键,反之亦然),以“覆盖”您的搜索模式(类似于数据库如何维护多个索引par表覆盖多种方式表可以查询。)
答案 2 :(得分:1)
我会为反方向添加第二个字典。即Dictionary<Node,int>
然后你要么
IEqualityComparer<Node>
并将其提供给词典Equals
GetHashCode
和Node
在这两种情况下,哈希码的良好实现对于获得良好的性能至关重要。
答案 3 :(得分:1)
您的解决方案不仅缓慢,而且错误。 Dictionary
中的项目顺序未定义,因此无法保证dict.Last()
返回最后添加的项目。 (虽然它通常看起来像那样。)
使用id来识别应用程序中的对象似乎也是错误的。您应该考虑直接使用对象的引用。
但是如果您想使用当前的设计并假设您根据latLng
比较节点,则可以创建两个词典:您已经拥有的词典和第二个词典Dictionary<latLng, int>
,可用于有效地了解某个节点是否已存在。如果确实如此,它会给你它的身份。
答案 4 :(得分:0)
您可以尝试使用HashSet<T>
答案 5 :(得分:0)
您可能需要考虑将其重组为仅使用List(其中'key'只是List的索引)而不是Dictionary。一些优点:
按整数键查找元素现在是O(1)(并且非常快O(1),因为它只是内部的数组解引用。)
插入新元素时,执行O(n)搜索以查看它是否已存在于列表中。如果没有,您还已经遍历了列表,并且可以记录您是否遇到了具有空记录的条目。如果有,则该索引是新密钥。如果不是,则新密钥是当前列表Count。您只是枚举集合一次而不是多次,枚举本身比枚举字典要快得多。