C# 设置允许在C中快速插入/删除和随机选择#

C# 设置允许在C中快速插入/删除和随机选择#,c#,data-structures,C#,Data Structures,我可以在C#中使用什么数据结构来允许快速插入/删除以及统一的随机选择?列表按元素删除的速度很慢(因为它每次都需要找到元素的索引),而哈希集似乎不允许随机选择元素(无需复制到列表) 数据结构将不断更新,因此插入和删除需要在线程序。似乎应该有一种方法将插入、删除和随机选择都设置为O(logn) 为对象分配任意整数键的二叉搜索树可以解决所有这些问题,但我在C#standard库中找不到合适的类。有没有一种规范的方法可以在不编写自定义二叉搜索树的情况下解决这个问题?在C#BCL中已经有一个BST,它被称

我可以在C#中使用什么数据结构来允许快速插入/删除以及统一的随机选择?列表按元素删除的速度很慢(因为它每次都需要找到元素的索引),而哈希集似乎不允许随机选择元素(无需复制到列表)

数据结构将不断更新,因此插入和删除需要在线程序。似乎应该有一种方法将插入、删除和随机选择都设置为O(logn)


为对象分配任意整数键的二叉搜索树可以解决所有这些问题,但我在C#standard库中找不到合适的类。有没有一种规范的方法可以在不编写自定义二叉搜索树的情况下解决这个问题?

在C#BCL中已经有一个BST,它被称为
SortedDictionary
,如果你不想要键值对,而是想要单个项,你可以使用
SortedSet
(SortedSet在.NET 4.0中)

从您的示例中,听起来您需要一个
SortedDictionary
。虽然我不确定你说的“统一随机选择”到底是什么意思

当然,
字典
是O(1),速度要快得多。所以,除非你们需要对键进行排序,否则我会使用它

更新:根据您的需求,您将在效率方面遇到第22条难题。为了能够跳转到数据结构中的随机连续索引中,您多长时间插入/删除一次?如果不经常使用,您可以使用数组并在(O(n log n))之后使用Sort(),或者始终按顺序(O(n))插入/删除

或者,您可以包装一个
字典
,并保留一个平行的
列表
,并在每次添加/删除后更新它:

_dictionary.Add(newIndex, newValue);
_indexes.Add(newIndex);
然后在查找时从列表中访问一个随机索引。很好的一点是,在这个方法中,Add()实际上是~O(1)(除非列表调整大小,但您可以设置初始容量以避免其中一些),但在删除时会产生O(n)开销

恐怕问题是,您要么牺牲查找时间,要么牺牲删除/插入时间。问题是所有最佳访问时间容器都是非连续的。不过,使用双
List/Dictionary
组合,您会有一个非常好的组合


更新2:从我们持续的讨论中可以看出,如果绝对性能是您的要求,您可能会有更好的运气推出自己的产品。不过考虑起来很有趣,如果我想到其他任何东西,我会更新。

二进制搜索树和派生结构,如
SortedDictionary
SortedSet
,通过比较键来操作

对象本身是不可比较的,但它们提供对象标识和哈希值。因此,
HashSet
是正确的数据结构。注意:
字典
是不合适的,因为删除会变成线性搜索(O(n)),并且不会解决删除后的随机问题

  • 插入是O(1)
  • 移除is O(1)
  • 随机元素是O(n)。它可以很容易地实现,例如

    set.ElementAt(random.Next(set.Count))
    
    无需复制到中间列表


我意识到这个问题已经有三年多的历史了,但只适用于浏览此页面的人:

如果不需要对数据集中的项目进行排序,可以使用
列表

插入和随机选择是O(1)。您可以在O(1)中删除,只需将最后一个项目移动到要删除的项目的位置,然后将其从末尾删除即可

代码:

使用系统;//随机的
使用System.Collections.Generic;//名单
//名单:
列表=新列表();
//添加x:
ItemType x=…;//要插入到列表中的项目
增加(x);
//随机选择
随机r=…;//可能是从别的地方弄来的
int index=r.Next(list.Count);
ItemType y=列表[索引];
//删除索引中的项目
列表[索引]=列表[列表.计数-1];//将最后一项复制到索引
list.RemoveAt(list.Count-1);//从列表末尾删除
编辑:当然,要从
列表中删除元素,您需要知道其索引。如果要删除随机元素,可以使用随机索引(如上例所示)。如果要删除给定项,可以保留一个
字典
,该字典将这些项映射到它们的索引。添加、删除和更新这些指数都可以在O(1)(摊销)中完成


这将导致所有操作的复杂性为O(1)(摊销)。

您的统一随机选择标准是什么?如果您可以使用键/值对,那么字典可能适合您的用途。我基本上只需要将所有对象放在一个帽子中,然后随机拉出一个(但将其放在帽子中)。出于此目的,对象没有结构;如果有必要,我可以将一个唯一的ID与每个对象关联,但这是一个没有意义的选择,我不需要排序顺序;元素自然没有“键”,它们只是数据对象。通过均匀随机选择,我的意思是,如果容器中有N个对象,我想以1/N的概率随机选择,我将得到任何给定的对象。要从字典中随机选择,我想我需要将KeyCollection()转换为一个列表,并执行类似keys的操作[random.Next(0,keys.Count())];但是,要么将KeyCollection转换为一个列表,要么首先创建KeyCollection将是O(n),不是吗?@Corey:然后您可以使用Dictionary并使用random类选择一个随机数并查找值。主要的问题是,如果你删除了一个项目,那么这个数字是否不再符合随机选择的条件?只是想知道索引是否会保持不变,但内容会改变?@Corey:我添加了一些更新。我认为,无论你做什么,没有一个基本的收藏可以做到这一点
using System; // For the Random
using System.Collections.Generic; // The List

// List:
List<ItemType> list = new List<ItemType>();

// Add x:
ItemType x = ...; // The item to insert into the list
list.Add( x );

// Random selection
Random r = ...; // Probably get this from somewhere else
int index = r.Next( list.Count );
ItemType y = list[index];

// Remove item at index
list[index] = list[list.Count - 1]; // Copy last item to index
list.RemoveAt( list.Count - 1 ); // Remove from end of list