If we have to delete a node from a binary tree, how should we handle the children of the node being deleted. E.g. in this tree:
100
/
10
/ \
5 20
where 100 is the root node, 10 is left child of 100, 5 is left child of 10 and 20 is right child of 10. So after deleting 10, what will happen to 5 and 20?
It is your choice if what should you do after deleting.You would probably want to move one of the child upward on some so certain criteria. Either of of Child will take place of parent.
delete node in Binary Search Tree.
delete node in AVL.
Heapify in Heapsort.
And more.
So it is always a choice you have to take to solve for objective.
Related
Example Tree image
Given a binary tree and pointer to a node (which is present) in tree, assume we have parent pointers. I have to find the number of iterations to delete the adjacent nodes and subsequent adjacent nodes of that deleted nodes. Here deleting means setting some flag, node -> burn. I wont delete the node.
Example :
1
/ \
2 3
/ \ / \
4 5 6 7
/ /
8 9
/
10
and given node in tree is 4,
The burned nodes in each iteration
In iteration 1:
For node 4: 4,8,2 (8 is the child node, 2 is parent of 4 , these are the adjacent nodes of 4).
In iteration 2:
For node 8: 10 will be burned. (4 is already burned)
For node 2: 5 and 1 will be burned.
This continues... , hence i have to find the number of iterations required to burn all nodes.
Not efficient but I think it will work:
Maintain a queue for the next nodes to be considered for deletion. And before deleting a node's adjacent nodes check whether they already have burn flag set.
Also, every time when you remove an item from queue:
check if all the nodes are burned or not (for this you can maintain a
Hash for faster access)
increment iteration count(which will be your result)
I have to build a binary tree but i don't know which node is parent, left child, or right child. I only know which nodes are connected. Example: for input like this:
6 4
5 7
9 7
1 5
10 4
3 4
2 6
7 8
5 6
(from 1 there is always one path) the tree should looks like that:
One the input i have also given number of nodes. Any ideas, tips?
From the list of the edges, one can easily create a tree.
You can find which are the leaf nodes, just search which nodes are appearing only in one edge.
But, it is not possible to know which of the leaf nodes is the head of the tree.
In a tree structure it is possible to choose any leaf, choose it as the head, and reorder the tree, and it'll be a valid tree.
There is also the issue of tree isomorphism, you can swap the right and left sub-trees to get a valid tree.
To summarize, from this list you can get 6 heads and in each 4 possible swaps, so in total 24 different valid trees.
I understand the idea when deleting a node that has two subtrees: I "erase" the node's value and replace it with either its predecessor from the left subtree's value or its successor from the right subtree's value, and then delete that node.
However, does it matter if I choose the successor from the right subtree or the predecessor from the left subtree? Or is either way valid as long as I still have a binary search tree after performing the deletion?
Both ways to perform a delete operation are valid if the node has two children.
Remember that when you get either the in-order predecessor node or the in-order successor node, you must call the delete operation on that node.
It doesn't matter which one you choose to replace. In fact you may need both.
Look at the following BST.
7
/ \
4 10
/ \ /
1 5 8
\
3
To delete 1, you need to replace 1 with right node 3.
And to delete 10, you need to replace 10 with left node 8.
Can you guys help me with some homework question I'm stuck in?
A local minimum in a full binary tree is defined as a node which is smaller than all of its neighbors (neighbors = parent, left child, right child).
I need to find a local minimum in a given full binary tree, which each of its nodes has a different number, in O(logn) complixity time.
Well, since the requirement is O(logn) then I tried to think of a way to go only through 1 path through the tree down to a leaf.
Or maybe I could look only at a half of the tree each time in a recursion and this way it will do the logn.
So say I have this in the tree:
70
/ \
77 60
There are 3 cases:
1) the root is smaller than both the left and the right child //then i'm done
2) the root is smaller only than the left
3) the root is smaller only than the right
The above tree is case 2.
So let's "throw away" the left subtree because there's no way the 77 can be a "local minimum" since it's greater than its parent.
So we're left with the right subtree. And so on, until we find the local minimum.
Problem here is, when we throw that left subtree, we could miss another local minimum down below. Here's an example:
70
/ \
77 60
/ \ / \
1 8 9 14
/ \ / \ / \ / \
3 4 5 6 2 7 15 13
So in this case, the only local minimum is "1", but we missed it because at the beginning we decided to search through the right subtree of the root.
By definition, a local min is a node whose value is smaller than that of any other nodes that are joined to it. Thus in your example, '1', '5', '6', '2', '7', '13' are all local minimums.
Once that's clear, the problem is simple.
First we check the root and see if it's smaller than both children. If yes, then we are done. If not, then we pick up its smaller child and recursively apply the check.
We terminate either 1) we found a node that is smaller than both of its children, or 2) we reach the bottom level (i.e. the leaves).
In case 1), the node at which we stop is the local min, because i) it's smaller than both of its children, and ii) it's smaller than its parent, which is the precondition of our deciding to check this node.
In case 2), we are left with two leaves (that are siblings), and at least one of them is smaller than the parent (otherwise the parent will be returned). Then, either (or both) of them are local min, as long as it's smaller than its parent.
Following this approach, at most 2 nodes per level are being looked at, thus requiring only O(log n) checks.
Hope this is helpful and clear enough.
"2" is considered as a local minimum if it has no children, if you want to find one within O(logn). Not possible to find "1" within O(logn)
I believe this can be done in O(N).
Start from the root. Check if it has a child that is smaller than it. If it has, go down to that child. If it doesn't have one, we are done.
Then, repeat this process by continuously choosing the child that is smaller than the current node. Check if it is the local min. If not, repeat.
By doing this, we guarantee that the current node's parent is always larger than itself. If the algorithm stops, there can be only two cases:
The current node is a leaf.
The two children of the current node are both larger than it.
In either cases, the current node is a local min.
EDIT:
Miss the "full" binary tree. Should be log(n).
Consider the deletion procedure on a BST, when the node to delete has two children. Let's say i always replace it with the node holding the minimum key in its right subtree.
The question is: is this procedure commutative? That is, deleting x and then y has the same result than deleting first y and then x?
I think the answer is no, but i can't find a counterexample, nor figure out any valid reasoning.
EDIT:
Maybe i've got to be clearer.
Consider the transplant(node x, node y) procedure: it replace x with y (and its subtree).
So, if i want to delete a node (say x) which has two children i replace it with the node holding the minimum key in its right subtree:
y = minimum(x.right)
transplant(y, y.right) // extracts the minimum (it doesn't have left child)
y.right = x.right
y.left = x.left
transplant(x,y)
The question was how to prove the procedure above is not commutative.
Deletion (in general) is not commutative. Here is a counterexample:
4
/ \
3 7
/
6
What if we delete 4 and then 3?
When we delete 4, we get 6 as the new root:
6
/ \
3 7
Deleting 3 doesn't change the tree, but gives us this:
6
\
7
What if we delete 3 and then 4?
When we delete 3 the tree doesn't change:
4
\
7
/
6
However, when we now delete 4, the new root becomes 7:
7
/
6
The two resulting trees are not the same, therefore deletion is not commutative.
UPDATE
I didn't read the restriction that this is when you always delete a node with 2 children. My solution is for the general case. I'll update it if/when I can find a counter-example.
ANOTHER UPDATE
I don't have concrete proof, but I'm going to hazard a guess:
In the general case, you handle deletions differently based on whether you have two children, one child, or no children. In the counter-example I provided, I first delete a node with two children and then a node with one child. After that, I delete a node with no children and then another node with one child.
In the special case of only deleting nodes with two children, you want to consider the case where both nodes are in the same sub-tree (since it wouldn't matter if they are in different sub-trees; you can be sure that the overall structure won't change based on the order of deletion). What you really need to prove is whether the order of deletion of nodes in the same sub-tree, where each node has two children, matters.
Consider two nodes A and B where A is an ancestor of B. Then you can further refine the question to be:
Is deletion commutative when you are considering the deletion of two nodes from a Binary Search Tree which have a ancestor-descendant relationship to each other (this would imply that they are in the same sub-tree)?
When you delete a node (let's say A), you traverse the right sub-tree to find the minimum element. This node will be a leaf node and can never be equal to B (because B has two children and cannot be a leaf node). You would then replace the value of A with the value of this leaf-node. What this means is that the only structural change to the tree is the replacement of A's value with the value of the leaf-node, and the loss of the leaf-node.
The same process is involved for B. That is, you replace the value of the node and replace a leaf-node. So in general, when you delete a node with two children, the only structural change is the change in value of the node you are deleting, and the deletion of the leaf node who's value you are using as replacement.
So the question is further refined:
Can you guarantee that you will always get the same replacement node regardless of the order of deletion (when you are always deleting a node with two children)?
The answer (I think) is yes. Why? Here are a few observations:
Let's say you delete the descendant node first and the ancestor node second. The sub-tree that was modified when you deleted the descendant node is not in the left sub-tree of the ancestor node's right child. This means that this sub-tree remains unaffected. What this also means is regardless of the order of deletion, two different sub-trees are modified and therefore the operation is commutative.
Again, let's say you delete the descendant node first and the ancestor node second. The sub-tree that was modified when you deleted the descendant node is in the left sub-tree of the ancestor node's right child. But even here, there is no overlap. The reason is when you delete the descendant node first, you look at the left sub-tree of the descendant node's right child. When you then delete the ancestor node, you will never go down that sub-tree since you will always be going towards the left after you enter the ancestor node's right-child's left sub-tree. So again, regardless of what you delete first you are modifying different sub-trees and so it appears order doesn't matter.
Another case is if you delete the ancestor node first and you find that the minimum node is a child of the descendant node. This means that the descendant node will end up with one child, and deleting the one child is trivial. Now consider the case where in this scenario, you deleted the descendant node first. Then you would replace the value of the descendant node with its right child and then delete the right child. Then when you delete the ancestor node, you end up finding the same minimum node (the old deleted node's left child, which is also the replaced node's left child). Either way, you end up with the same structure.
This is not a rigorous proof; these are just some observations I've made. By all means, feel free to poke holes!
It seems to me that the counterexample shown in Vivin's answer is the sole case of non-commutativity, and that it is indeed eliminated by the restriction that only nodes with two children can be deleted.
But it can also be eliminated if we discard what appears to be one of Vivin's premises, which is that we should traverse the right subtree as little as possible to find any acceptable successor. If, instead, we always promote the smallest node in the right subtree as the successor, regardless of how far away it turns out to be located, then even if we relax the restriction on deleting nodes with fewer than two children, Vivin's result
7
/
6
is never reached if we start at
4
/ \
3 7
/
6
Instead, we would first delete 3 (without successor) and then delete 4 (with 6 as successor), yielding
6
\
7
which is the same as if the order of deletion were reversed.
Deletion would then be commutative, and I think it is always commutative, given the premise I have named (successor is always smallest node in right subtree of deleted node).
I do not have a formal proof to offer, merely an enumeration of cases:
If the two nodes to be deleted are in different subtrees, then deletion of one does not affect the other. Only when they are in the same path can the order of deletion possibly affect the outcome.
So any effect on commutativity can come only when an ancestor node and one of its descendants are both deleted. Now, how does their vertical relationship affect commutativity?
Descendant in the left subtree of the ancestor. This situation will not affect commutativity because the successor comes from the right subtree and cannot affect the left subtree at all.
Descendant in the right subtree of the ancestor. If the ancestor's successor is always the smallest node in the right subtree, then order of deletion cannot change the choice of successor, no matter what descendant is deleted before or after the ancestor. Even if the successor to the ancestor turns out to be the descendant node that is also to be deleted, that descendant too is replaced with the the next-largest node to it, and that descendant cannot have its own left subtree remaining to be dealt with. So deletion of an ancestor and any right-subtree descendant will always be commutative.
I think there are two equally viable ways to delete a node, when it has 2 children: SKIP TO CASE 4...
Case 1: delete 3 (Leaf node)
2 3
/ \ --> / \
1 3 1
Case 2: delete 2 (Left child node)
2 3
/ \ --> / \
1 3 1
Case 3: delete 2 (Right child node)
2 2
/ \ --> / \
1 3 3
______________________________________________________________________
Case 4: delete 2 (Left & Right child nodes)
2 2 3
/ \ --> / \ or / \
1 3 1 3
BOTH WORK and have different resulting trees :)
______________________________________________________________________
As algorithm explained here: http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Trees/AVL-delete.html
Deleting a node with 2 children nodes:
1) Replace the (to-delete) node with its in-order predecessor or in-order successor
2) Then delete the in-order predecessor or in-order successor
I respond here to Vivin's second update.
I think this is a good recast of the question:
Is deletion commutative when you are
considering the deletion of two nodes
from a Binary Search Tree which have a
ancestor-descendant relationship to
each other (this would imply that they
are in the same sub-tree)?
but this bold sentence below is not true:
When you delete a node (let's say A),
you traverse the right sub-tree to
find the minimum element. This node
will be a leaf node and can never be equal to B
since the minimum element in A's right subtree can have a right child. So, it is not a leaf.
Let's call the minimum element in A's right subtree successor(A).
Now, it is true that B cannot be successor(A), but it can be in its right subtree. So, it is a mess.
I try to summarize.
Hypothesis:
A and B have two children each.
A and B are in the same subtree.
Other stuff we can deduce from hypothesis:
B is not successor(A), neither A is successor(B).
Now, given that, i think there are 4 different cases (as usual, let be A an ancestor of B):
B is in A's left subtree
B is an ancestor of successor(A)
successor(A) is an ancestor of B
B and successor(A) don't have any relationship. (they are in different A's subtrees)
I think (but of course i cannot prove it) that cases 1, 2 and 4 don't matter.
So, only in the case successor(A) is an ancestor of B deletion procedure could not be commutative. Or could it?
I pass the ball : )
Regards.