我正在寻找以下任务的已知算法:
X
,它为我提供了两种方法:
take()
返回未采用的最小自然数,即此方法的顺序调用将返回1
,2
,3
等等。free(n)
标记n
如果已经拍摄则不会拍摄,或者如果之后没有拍摄则会引发异常,或者在此之后被释放。示例:
take = 1
take = 2
take = 3
free(2)
take = 2
take = 4
free(3)
free(2)
free(1)
take = 1
take = 2
take = 3
take = 5
free(6) : exception
我发明了bit-set-b-tree(不确定如何正确调用它),其中leaves包含为所有捕获的数字设置的实际位,而其他节点则为了搜索目的而分组。每个非叶节点都有32个子节点,因此叶位集中每个位的内存开销是1/31位。
实际搜索“洞”'在节点(叶子和非叶子)中完成基于位操作的二进制搜索,其执行log2(32) = 5
操作,而从根到叶子的遍历节点需要log32(L)
其中L
是最后一个被采取的号码'状态。
因此,两个操作都需要5*log32(L)
,并且需要大约1.032*L
个位才能将该结构存储在内存中。在最坏的情况下,L不能同时大于最大数量。即使除了一个数字之外所有数字都被释放,它也不会减少,但如果此时从未超过10个数字,则L将小于或等于10。
你怎么看待我重新发明轮子?
我之所以需要这种结构是一个非常具体的id生成,但可能还有其他的应用?这是一个额外的问题:)
感谢您的关注。
答案 0 :(得分:0)
看起来很有效率。
每个非叶子节点平均少于32个孩子。 32对于叶子的二进制搜索时间是正确的最大值,但是可能在5 * log d (L)中使用一些较小的数字d作为基数,无论是平均密度还是最小密度。
答案 1 :(得分:0)
您还可以对已释放的数字使用排序列表。
设n表示take()函数返回的最大数。 每次调用free(d)时,首先在排序列表中搜索d并在必要时抛出异常!否则,将d插入排序列表。整个操作的成本为O(log n)。
现在,每次调用take()函数时,只需返回其中的最小数字,并使用cost O(1)返回delete-min。如果排序列表为空,则递增n并返回它。
请注意,在这种方法中,它们没有内存开销:)