Red-black tree - How to find the node's parent?
In red-black tree, when rotate, you need to know who is the parent of particular node. However, the node only has reference to either right or left child.
I was thinking to give a node instance variable "parent" but just for this reason I don't think it is worth doing so and also it would be too complicated to change parent reference per rotation.
public class Node {
private left;
private right;
private isRed;
private parent; //I don't think this is good idea
}
So, my solution is to write findParent() method that use search to find parent. I am wondering if there is any other way to find a 开发者_开发百科node's parent?
My solution:
sample tree:
50
/ \
25 75
If you want to find parent of Node 25, you pass something like:
Node parent = findParent(Node25.value);
and it returns node50.
protected Node findParent(int val) {
if(root == null) {
return null;
}
Node current = root;
Node parent = current;
while(true) {
if(current.val == val) { //found
return parent;
}
if(current == null) { //not found
return null;
}
parent = current;
if(current.val > val) { //go left
current = current.left;
}
else { //go right
current = current.right;
}
}
}
The use of a parent pointer is optional. If you forgo the parent pointer then you will have to write insert/delete operations using recursion (the recursive method calls preserve the parent information on the stack) or write an iterative version which maintains its own stack of parents as it moves down the tree.
A very good description of red-black trees can be found here
http://adtinfo.org/
That includes descriptions of a number of rbtree implementations including with and without parent pointers.
If you do want to save on space (and that is fair enough) a really excellent description of an rbtree implementation can be found here
http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
The method you have described for searching for a node's parent would be very inefficient if used by the insert/delete implementations. Use a pointer or use recursion.
I was thinking to give a node instance variable "parent" but just for this reason I don't think it is worth doing so
Having your nodes have a parent
reference requires one extra pointer/reference per node. Compare this with needing to traverse the tree whenever you need to know the parent for a given node.
This is then a trade-off between
- The cost of maintaining an extra reference, and keeping it up to date whenever you modify a node.
- The computational cost and complexity of having to traverse the tree to find a parent of a given node
I think that the choice between these two options is somewhat subjective but personally I would choose to simply keep track of the parent
references.
As a point of reference for you, java.util.TreeMap
is implemented as a Red-Black tree which Entry
nodes that contain left
, right
, and parent
references.
As you traverse the tree to get to your pivot node you can cache the previous parent or if you need more than one level of "undo" you could cache each traversed node on to a stack.
This cache would be a variable local to your rotation algorithm so it wouldn't require any more space in the tree or expensive additional traversals.
It's definitely better to store the parent than to look it up. Updating parent reference is not that complex.
Another solution, besides parent pointers and querying the parent all over again is to maintain an ancestor stack.
Suppose someone wishes to insert 23 into the following tree:
Red Black Tree
Generally the algorithm to insert is:
Find node where 23 would be if it is in the tree
If 23 is already there, return failure
If 23 is not already there, put it there.
Run your re-balancing/coloring routine as needed.
Now, to use the stack approach, you allocate a stack big enough to support one node per level of your tree (I think 2 * Ceiling(Log2(count)) + 2) should have you covered. You could even keep a stack allocated for insertion or deletion and just clear it whenever you start an insertion.
So -- Look at the root. Push it onto the stack. 23 is greater than value in the root, so go right. Now push node current node (value 21) onto the stack. If 23 is in the tree, it must be to the right of current node. But the node to the right of the current node is a null-sentinel. Thus, that null-sentinel should be replaced with a node with your value. The parent is the item on the top of the stack (most recently pushed), the grandparent is next in line ... etc. Since you seem to be learning ... Java supplies a stack interface for you so you won't need to develop your own stack to do this. Just use theirs.
As to whether this is better than the parent pointer approach, that seems debatable to me -- I would lean to the parent pointer approach for simplicity and elimination of the need to maintain an ancillary data structure or use recursion extensively. That said, either approach is better than querying the parent of the current node as you apply your re-balancing/coloring routine.
精彩评论