这个问题是关于我想到的数据结构。它是一个动态数组,如std :: vector<>在C ++中,除了删除算法不同。
在正常的动态数组中,当一个元素被移除时,所有剩余的元素必须向下移动,即O(n),除非它是最后一个元素,它将是O(1)。
在这一个中,如果删除了任何元素,它将被最后一个元素替换。这当然会失去对元素的排序。但现在删除任何元素都是不变的时间。
列表将具有相同的删除时间,但此结构具有随机访问权限。唯一需要注意的是你不知道你正在访问什么,因为订购可能是混乱的,所以无论如何使用随机访问。另外,列表不会搞乱元素的任何指针/迭代器。
嗯,这个结构看起来相当无用,除了严格走过各个元素并且可能沿着路径移除它们的非常具体的任务。列表可以执行相同的操作,但这具有更好的缓存性能。
那么,这个奇怪/无用的结构是否有名称,是否有任何用途?或者只是一场不错的小脑风暴?
答案 0 :(得分:5)
这个想法在Knuth (Fisher–Yates) shuffle中使用。随机拾取的元素将替换为数组中的最后一个元素。因为无论如何我们想要的是随机排列,重新排序并不重要。
答案 1 :(得分:3)
那么,这个奇怪/无用的结构是否有名称,是否有任何用途?
我在多进程系统的模拟中使用了类似的东西。
在作为状态机实现的进程的调度程序中,每个进程都在等待外部事件,活动或已完成。调度程序有一个指向进程的指针数组。
最初每个进程都是活动的,并且调度程序具有最后等待和第一个完成进程的索引,最初为零和数组的长度。
V-- waiting
[ A-active, B-active, C-active, D-active ]
completed --^
^- run
要使进程进入下一个状态,调度程序将遍历数组并依次运行每个进程。如果进程报告它正在等待,则在数组中的最后一个等待进程之后将其与进程交换。
V-- waiting
[ A-waiting, B-active, C-active, D-active ]
completed --^
^- run
如果它报告已完成,则在第一个完成的阵列之前与进程交换。
V-- waiting
[ A-waiting, D-active, C-active, B-completed ]
completed --^
^- run
因此,当调度程序运行并处理从活动状态到等待或完成的转换时,数组将按顺序排列,包括开始时的所有等待进程,中间的所有活动进程以及结束时已完成的进程。
V-- waiting
[ A-waiting, C-waiting, D-active, B-completed ]
completed --^
^- run
在一定次数的迭代之后,或者当没有更多活动进程时,已完成的进程将从数组中清除,并处理外部事件:
V-- waiting
[ A-waiting, C-waiting, D-completed, B-completed ]
completed --^
^- run == completed so stop
这类似于它使用交换从集合中删除项目,但它从两端移除项目而将“集合”留在中间。
答案 2 :(得分:2)
我记得以前用过很多次这种方法。但我不知道它的名字。
简单的例子:在计算机游戏中,你正在迭代所有“坏人”并计算他们的动作等。他们可能发生的一件事就是消失(他们的尸体消失了,现在已经99%透明了)。此时,您将其从列表中删除,并在不增加迭代计数器的情况下恢复迭代器。
在删除项目时,在Binary Heap中完成了与此类似的操作,但是下一步是维护堆规则 - O(log n)。
答案 3 :(得分:0)
我不知道它的名字,但在某些情况下它比列表更好。
特别是,对于非常小的数据,这将远远优于单链或双链表。 因为您连续存储所有内容,所以每个元素没有额外的指针开销。
答案 4 :(得分:-1)
嗯,那算法真的有O(1)删除时间吗?
这意味着
...这在我能想到的任何数据结构中都是不可能的。虽然双链表可以满足这些约束,但是你已经有了一个指向要删除的元素的指针。
答案 5 :(得分:-1)
它被称为Set。