考虑二叉搜索树,其中所有键都是唯一的。节点没有父指针
我们有最多n / 2个标记节点
我可以在O(n 2 )时删除所有这些(使用postorder遍历,当遇到标记的节点时,在O(n)处删除)。但这是不合适的。
我需要一个算法来删除 O(n)时间内所有标记的节点。
谢谢。
编辑删除后我需要保持节点顺序不变。
EDIT-2 因此看起来我应该使用典型删除删除每个标记的节点(在左子树中查找最右边的节点并将其与要删除的节点交换)。
答案 0 :(得分:6)
有许多方法,但这里有一个应该很容易正确的方法,并给你一个完美平衡的树作为副作用。但是,它需要线性额外空间。
更新:忘了说跳过标记的元素,但这很明显,对吧? ;)
答案 1 :(得分:2)
我找到了怎么做!
static class LinearDeletion {
public static Node MIN_VALUE = new Node(Integer.MIN_VALUE);;
boolean toFindMax = false;
Node parentOfMax = null;
Node max = MIN_VALUE;
Stack<Object> stack = new Stack<>();
public void perform(Node x, Node parent) {
if (x.isToDelete) {
stack.push(toFindMax);
stack.push(parentOfMax);
stack.push(max);
toFindMax = true;
parentOfMax = null;
max = MIN_VALUE;
if (x.left != null) {
perform(x.left, x);
}
if (x.left == null) { //deletion of the node
if (parent.left == x) {
parent.left = x.right;
} else {
parent.right = x.right;
}
} else {
if (x.right == null) {
if (parent.left == x) {
parent.left = x.left;
} else {
parent.right = x.left;
}
} else {
x.key = max.key;
x.isToDelete = max.isToDelete;
if (parentOfMax != x) {
parentOfMax.right = max.left;
} else {
x.left = max.left;
}
}
} // end of deletion
max = (Node) stack.pop();
parentOfMax = (Node) stack.pop();
toFindMax = (boolean) stack.pop();
if (toFindMax) { // check if the current node is the maximum
if (x.key > max.key) {
max = x;
parentOfMax = parent;
}
}
if (x.right != null) {
perform(x.right, x);
}
} else {
if (x.left != null) {
perform(x.left, x);
}
if (toFindMax) {
if (x.key > max.key) {
max = x;
parentOfMax = parent;
}
}
if (x.right != null) {
perform(x.right, x);
}
}
}
}
答案 2 :(得分:1)
我不明白为什么后序遍历为O(n 2 )。删除单个节点的原因是O(n)是您需要遍历树以查找节点,这是一个O(n)操作。但是一旦找到一个节点,它就可以在O(1)时间内被删除。 * 因此,你可以在O(n)时间内在一次遍历中删除所有O(n)个标记的节点。 / p>
* 除非你需要维护一棵平衡的树。但是,您不能将其列为要求。
编辑正如@njlarsson在评论中正确指出的那样,即使找到节点,删除操作通常也不是O(1)。然而,由于在访问要删除的节点之前遍历左子树和右子树,因此可以在子树遍历期间无需额外成本地获得子树的最小(或最大)元素。这样可以删除O(1)。