Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 实施智能列表_Algorithm_Data Structures_Random Sample - Fatal编程技术网

Algorithm 实施智能列表

Algorithm 实施智能列表,algorithm,data-structures,random-sample,Algorithm,Data Structures,Random Sample,我被要求设计一个名为“聪明列表”的数据结构,该结构保存具有真实键号的项,并提供下一步操作: 插入(x)-在列表中插入新元素。应该在O(日志n)中 删除最小/最大值-删除并返回列表中的最小/最大值元素。应在O(对数n)时间内 Transform-更改remove min/max的返回对象(如果为min,则为max,反之亦然)。应该在O(1)中 随机采样(k)-返回列表中随机选择的k个元素(k大于0小于n)。应该是O(min(k log k,n+(n-k)log(n-k))) 关于结构的假设: 数据

我被要求设计一个名为“聪明列表”的数据结构,该结构保存具有真实键号的项,并提供下一步操作:

插入(x)-在列表中插入新元素。应该在O(日志n)中

删除最小/最大值-删除并返回列表中的最小/最大值元素。应在O(对数n)时间内

Transform-更改remove min/max的返回对象(如果为min,则为max,反之亦然)。应该在O(1)中

随机采样(k)-返回列表中随机选择的k个元素(k大于0小于n)。应该是O(min(k log k,n+(n-k)log(n-k)))

关于结构的假设: 数据结构在任何阶段都不会容纳超过3n个元素。 我们不能假设n=O(1)。 我们可以使用Random()方法,它在O(1)时间内返回一个介于[0,1]和preforms之间的实数

我设法实现了前三种方法,使用了一个最小-最大精细堆。但是,在这个时间限制内,我对随机抽样(k)方法一无所知。我能找到的只是“”,它在O(n)时间内运行


有什么建议吗?

如果您将数字存储在一个数组中,并使用自平衡二叉树来维护这些数字的排序索引,那么您可以按照给定的时间复杂度执行所有操作。在树的节点中,您需要指向数字数组的指针,在数组中,您需要指向树节点的指针那号码是属于你的

  • Insert(x)将x添加到数组的末尾,然后将其插入到二叉树中
  • Remove min/max跟随二叉树的左/右分支查找最小值或最大值,然后将其删除。您需要将数组中的最后一个数字交换到删除生成的孔中。此时,您需要将数组中的后指针返回到树中
  • Transform为“删除最小值/最大值”操作切换一位
  • 随机样本选择0…n-1范围内的k或(n-k)唯一整数(取决于2k是否
假设(未初始化的)内存可以在O(1)时间内分配,则可以在O(k)时间内创建范围为0..n的k个唯一整数集

首先,假设您有办法知道内存是否未初始化。然后,您可以拥有一个大小为n的未初始化数组,并执行Fisher-Yates shuffle的常规k步,除非每次访问数组的元素(例如,索引i),如果未初始化,则可以将其初始化为值i。这样可以避免初始化整个数组,从而允许在O(k)时间而不是O(n)时间内完成洗牌

第二,显然,通常不可能知道内存是否未初始化,但有一个技巧可以让你在未初始化的内存中实现稀疏数组(代价是使用的内存量翻倍)。Russ Cox的博客对此进行了深入描述:

这为您提供了一种随机选择k个数字的O(k)方法。如果k较大(即:>n/2),您可以选择(n-k)个数字而不是k个数字,但您仍然需要将未选择的数字返回给用户,如果您将其复制出去,则始终是O(k),因此选择速度越快,您将一无所获


如果您不介意提供对内部数据结构的访问权限,一种更简单的方法是在底层数组上执行Fisher-Yates shuffle的k或n-k步骤(取决于k是否您可以使用数组中实现的最小-最大堆(包括随机采样)来完成所有这些操作

对于随机抽样,选择一个从0到n的随机数。这是您要删除的项的索引。复制该项,然后用数组中的最后一项替换该索引处的项,并减少计数。现在,根据需要将该项向上冒泡或向下筛选

如果它在最小级别,并且该项比其父项小,则将其冒泡。如果它比最小的子项大,则将其筛选。如果它在最大级别,则反转逻辑

该随机抽样是O(k log n)。也就是说,您将从n个项的堆中删除k个项。它的复杂性与对
delete min
的k个调用相同

附加信息 如果不必从列表中删除项目,则可以通过从数组中选择
k
索引,在O(k)中进行简单的随机抽样。但是,可能存在重复。为避免重复,可以执行以下操作:

随机选择一个项目时,将其与数组中的最后一个项目交换,并将计数减少1。选择所有项目后,它们位于数组的最后
k
位置。这显然是一个O(k)操作。您可以复制那些要由函数返回的项。然后,将count设置回原始值,并调用您的
MakeHeap
函数,该函数可以从O(n)中的任意数组构建堆。因此,您的操作是O(k+n)

MakeHeap
函数非常简单:

for (int i = count/2; i >= 0; --i)
{
    SiftDown(i);
}
另一个选项是,当您进行交换时,在堆栈上保存交换操作。也就是说,保存from和to索引。要放回项目,只需按相反顺序运行交换(即从堆栈中弹出,交换项目,然后继续,直到堆栈为空)。这是选择的O(k),放回的O(k)和O(k)堆栈的额外空间

当然,另一种方法是按照我的建议进行删除,一旦所有删除都完成,您就可以将项目重新插入堆中