C# 检查重复项时的性能

C# 检查重复项时的性能,c#,performance,collections,.net-2.0,C#,Performance,Collections,.net 2.0,我一直在从事一个项目,在这个项目中,我需要遍历一组数据,并删除“主键”重复的条目。我试过使用 List<int> 列表 及 字典 使用字典,我发现性能稍好一些,尽管我从不需要为每个条目标记布尔值。我的期望是,这是因为列表允许索引访问,而字典不允许。我想知道的是,有没有更好的办法来解决这个问题。我不需要再次访问条目,我只需要跟踪我看到的“主键”,并确保我只对具有新主键的条目执行添加工作。我正在使用C#和.NET2.0。我无法控制修复输入数据以从源中删除重复数据(不幸的是!)。因此

我一直在从事一个项目,在这个项目中,我需要遍历一组数据,并删除“主键”重复的条目。我试过使用

List<int>
列表

字典

使用字典,我发现性能稍好一些,尽管我从不需要为每个条目标记布尔值。我的期望是,这是因为列表允许索引访问,而字典不允许。我想知道的是,有没有更好的办法来解决这个问题。我不需要再次访问条目,我只需要跟踪我看到的“主键”,并确保我只对具有新主键的条目执行添加工作。我正在使用C#和.NET2.0。我无法控制修复输入数据以从源中删除重复数据(不幸的是!)。因此,您可以对扩展有一种感觉,总的来说,我在应用程序中检查了大约1000000次重复项,但在不超过64000的子集中,需要是唯一的。

他们在.NET 3.5中添加了HashSet类。但我想这将与字典一致。如果少于100个元素,列表的性能可能会更好。

他们在.NET3.5中添加了HashSet类。但我想这将与字典一致。如果少于100个元素,列表的性能可能会更好。

我真的不明白你的要求

首先,这与你所说的正好相反。字典具有索引访问权限(是哈希表),而de List没有

如果字典中已有数据,则所有键都是唯一的,不能有重复项

我想您将数据存储在另一种数据类型中,并将其存储到字典中。如果是这种情况,插入数据将使用两个字典

foreach (int key in keys)
{
  if (!MyDataDict.ContainsKey(key))
  {
    if (!MyDuplicatesDict.ContainsKey(key))
      MyDuplicatesDict.Add(key);
  }
  else
    MyDataDict.Add(key); 
}

我真的不明白你的要求

首先,这与你所说的正好相反。字典具有索引访问权限(是哈希表),而de List没有

如果字典中已有数据,则所有键都是唯一的,不能有重复项

我想您将数据存储在另一种数据类型中,并将其存储到字典中。如果是这种情况,插入数据将使用两个字典

foreach (int key in keys)
{
  if (!MyDataDict.ContainsKey(key))
  {
    if (!MyDuplicatesDict.ContainsKey(key))
      MyDuplicatesDict.Add(key);
  }
  else
    MyDataDict.Add(key); 
}

编辑:不要删除我的评论。我以为你是在讲C++。我不知道我的帖子是否与C#world相关。

哈希表可能会快一点。由于访问内存的方式,二叉树(这就是字典中使用的)往往相对较慢。如果你的树变得很大,这一点尤其正确

但是,在更改数据结构之前,您是否尝试为字典使用自定义池分配器?我打赌时间不是花在遍历树本身上,而是花在字典将为您提供的数百万次分配和解除分配上

只需将一个简单的池分配器插入字典模板,您就可以看到10倍的速度提升。Afaik boost有一个可以直接使用的组件

另一种选择:如果您知道整数中只有64.000个条目,那么您可以将它们写入一个文件,并为其创建一个完美的哈希函数。这样,您就可以使用哈希函数将整数映射到0到64.000范围,并为位数组编制索引


可能是最快的方式,但灵活性较低。每次更改整数集时,您必须重新执行完美的哈希函数(可以自动完成)。

编辑:无需删除我的注释。我以为你是在讲C++。我不知道我的帖子是否与C#world相关。

哈希表可能会快一点。由于访问内存的方式,二叉树(这就是字典中使用的)往往相对较慢。如果你的树变得很大,这一点尤其正确

但是,在更改数据结构之前,您是否尝试为字典使用自定义池分配器?我打赌时间不是花在遍历树本身上,而是花在字典将为您提供的数百万次分配和解除分配上

只需将一个简单的池分配器插入字典模板,您就可以看到10倍的速度提升。Afaik boost有一个可以直接使用的组件

另一种选择:如果您知道整数中只有64.000个条目,那么您可以将它们写入一个文件,并为其创建一个完美的哈希函数。这样,您就可以使用哈希函数将整数映射到0到64.000范围,并为位数组编制索引


可能是最快的方式,但灵活性较低。每次更改整数集时,都必须重新执行完美的哈希函数(可以自动完成)。

如果要检查整数的唯一性,并且整数的范围受到足够的约束,则可以使用数组

为了更好地打包,您可以实现位图数据结构(基本上是一个数组,但数组中的每个int表示键空间中的32 int,每个键使用1位)。这样,如果最大数量为1000000,则数据结构只需要约30.5KB的内存


位图的执行次数将是O(1)(每次检查),这是很难打败的。

如果您正在检查整数的唯一性,并且整数的范围受到足够的约束,那么您可以使用数组

为了更好地打包,您可以实现位图数据结构(基本上是一个数组,但数组中的每个int表示键空间中的32 int,每个键使用1位)。这样,如果最大数量为1000000,则数据结构只需要约30.5KB的内存


位图的性能将是O(1)(每次检查),这是很难击败的。

有一个问题。出于问题的目的,性能不是一个重要的考虑因素,但是您可能想看看答案,因为它们可能会给您一些想法。还有,我可能要离开b
 // initailize to a size if you know your set size
List<int> FoundKeys = new List<int>( 64000 );
Dictionary<int,int> FoundDuplicates = new Dictionary<int,int>();

foreach ( int Key in MyKeys )
{
   // this is an O(log N) operation
   int index = FoundKeys.BinarySearch( Key );
   if ( index < 0 ) 
   {
       // if the Key is not in our list, 
       // index is the two's compliment of the next value that is in the list
       // i.e. the position it should occupy, and we maintain sorted-ness!
       FoundKeys.Insert( ~index, Key );
   }
   else 
   {
       if ( DuplicateKeys.ContainsKey( Key ) )
       {
           DuplicateKeys[Key]++;
       }
       else
       {
           DuplicateKeys.Add( Key, 1 );
       }
   } 
}