Algorithm 实施智能列表
我被要求设计一个名为“聪明列表”的数据结构,该结构保存具有真实键号的项,并提供下一步操作: 插入(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)时间内运行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))) 关于结构的假设: 数据
有什么建议吗?如果您将数字存储在一个数组中,并使用自平衡二叉树来维护这些数字的排序索引,那么您可以按照给定的时间复杂度执行所有操作。在树的节点中,您需要指向数字数组的指针,在数组中,您需要指向树节点的指针那号码是属于你的
- Insert(x)将x添加到数组的末尾,然后将其插入到二叉树中
- Remove min/max跟随二叉树的左/右分支查找最小值或最大值,然后将其删除。您需要将数组中的最后一个数字交换到删除生成的孔中。此时,您需要将数组中的后指针返回到树中
- Transform为“删除最小值/最大值”操作切换一位
- 随机样本选择0…n-1范围内的k或(n-k)唯一整数(取决于2k是否
如果您不介意提供对内部数据结构的访问权限,一种更简单的方法是在底层数组上执行Fisher-Yates shuffle的k或n-k步骤(取决于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)堆栈的额外空间
当然,另一种方法是按照我的建议进行删除,一旦所有删除都完成,您就可以将项目重新插入堆中