【问题标题】:How is lazy deletion advantageous/disadvantageous to a binary tree or linked list?延迟删除对二叉树或链表有什么好处/坏处?
【发布时间】:2011-12-05 16:16:30
【问题描述】:
最近,对于一个数据结构类,我被问到一个懒惰删除(即首先标记需要删除的项目,然后在稍后删除所有标记的项目的删除)如何会的问题对数组、链表或二叉树有利/不利。这是我想出的:
- 这将有助于数组,因为您可以节省每次删除索引时移动数组所花费的时间,尽管在需要遍历数组的算法中,可能会效率低下。
- 这对链接列表没有帮助,因为您需要遍历 O(n) 来标记要删除的项目。
- 我不完全确定二叉树,但如果它是二叉树的链表实现,我会想象它就像链表?
【问题讨论】:
标签:
arrays
linked-list
binary-tree
【解决方案1】:
我认为这完全取决于情况和要求。一般来说,使用这种方法,它们被标记然后删除,它们都有很多相似的优点和缺点。
类似的优点:
- 当标记为删除时,数据结构不会移动,这使得删除速度更快。
- 您可以在已删除项目的顶部插入,这意味着插入也不会移动,而且插入可以更快地完成,因为它可以覆盖第一个删除而不是查找列表的末尾
类似的缺点:
- 删除的项目浪费空间,因为他们只是坐在那里
- 必须横向两次删除一个项目,一次标记它,再一次删除它
- 许多标记的删除项目会污染数据结构,导致搜索时间更长,因为必须搜索已删除的项目。
【解决方案2】:
出于各种原因,我认为答案将是“取决于”,但我认为您走在正确的轨道上。
1) 我同意您关于数组的回答,假设要求您的数组中没有孔。如果您不需要在每次删除时移动数组,那么现在建议的标记,稍后删除的方法根本没有帮助。无论哪种方式,您都在处理 O(n) 与 (2O(n) = O(n)) 的算法,它们是相等的。真正要考虑的是“一次重新排序所有删除内容与单独重新排序每个删除内容是否可以节省您的时间?”假设 m 是删除次数,那么对于立即删除方法,数组中第一次删除后的每个元素重新排序的次数是 O(m),而现在标记为 O(1),稍后删除方法。
2) 我同意您对链表的回答。
3) 至于二叉树,我想这取决于它是什么类型。如果您使用的是排序平衡的二叉树,则必须考虑与上述 1) 相同的问题,但如果不是,则您的想法是正确的,它的行为应该与链表完全一样。
【解决方案3】:
也许您需要更深入地考虑一下链表的实现。您指出延迟删除不会有任何帮助,因为搜索时间是执行删除所必需的所有时间。
想想实际从链表中删除一个项目需要什么。
注意:这假设一个单链表(不是双链表)
1)找到要删除的项(因为这是一个单链表,所以总是要搜索,因为需要PREV项)
2) 保留指向 PREV 和 NEXT 元素的指针
3) 将“PREV”元素固定为指向 NEXT 元素 - 因此,隔离了 CURRENT 元素
3.5) 在双链表中,您还必须注意指向 PREV 元素的 NEXT 元素。
4) 释放与当前元素关联的内存
现在,延迟删除的过程是什么? - - 矮得多
1)找到要删除的项目(您甚至可能不必执行搜索,因为您已经有了指向要删除的对象的指针?)
2) 标记要删除的项目。
*) 等待“垃圾收集”线程运行并在系统处于“空闲”状态时实际执行剩余步骤
实现为链表的二叉树,其中每个元素都有左和右 - 但是,您仍然在搜索中执行相同的步骤。我相信,使用 O(Log(n)) 进行二叉树搜索会更有效。
但是,从这些中删除变得更加复杂,因为您需要处理更多指针(“左”和“右”) - 因此需要更多指令来修复,特别是当您删除具有指向左右节点的指针——其中一个需要提升到新的根节点——但是,如果它们都已经分配了左右指针怎么办?原来的“左/右”节点去哪儿了? - 此时您必须重新平衡树。因此,从用户的角度来看,删除标记和“空闲”垃圾收集处理内存细节(因此用户不必等待)可以显着节省。