package
algorithms.tree;
/**
* R-B Tree has following four rules:
* 1)every node is either red or black
* 2)root and empty node (external leaf node) are always black.
* 3)the red node's parent node must be black
* 4)every simple path start from node X to its descendant contains same number of black node
*
*
*
@author
yovn
*
*/
public
class
RBTree
<
E
extends
Comparable
<
E
>>
extends
DefaultBSTree
<
E
>
implements
BSTree
<
E
>
{
public
static
class
RBPrinter
<
E
extends
Comparable
<
E
>>
implements
DefaultBSTree.NodeVisitor
<
E
>
{
@Override
public
void
visit(E ele) {
}
@Override
public
void
visitNode(algorithms.tree.DefaultBSTree.BSTNode
<
E
>
node) {
RBNode
<
E
>
n
=
(RBNode
<
E
>
)node;
if
(
!
n.isNull())
System.out.print(n.key
+
"
(
"
+
(n.color
==
RBNode.RED
?
"
RED
"
:
"
BLACK
"
)
+
"
),
"
);
}
}
static
class
RBNode
<
E
extends
Comparable
<
E
>>
extends
BSTNode
<
E
>
{
static
final
boolean
RED
=
false
;
static
final
boolean
BLACK
=
true
;
RBNode
<
E
>
parent;
boolean
color;
//
red or black
RBNode(RBNode
<
E
>
p,E key,
boolean
color) {
super
(key);
this
.color
=
color;
this
.parent
=
p;
}
final
boolean
isNull(){
return
key
==
null
;}
}
@Override
public
final
boolean
delete(E ele) {
RBNode
<
E
>
cur;
int
cmp;
if
(root
==
null
)
return
false
;
cur
=
(RBNode
<
E
>
)root;
while
(
!
cur.isNull()
&&
(cmp
=
ele.compareTo(cur.key))
!=
0
)
{
if
(cmp
<
0
)cur
=
(RBNode
<
E
>
)cur.left;
else
cur
=
(RBNode
<
E
>
)cur.right;
}
if
(cur.isNull())
{
//
can't find specified key
return
false
;
}
if
(
!
((RBNode
<
E
>
)cur.left).isNull()
&&!
((RBNode
<
E
>
)cur.right).isNull())
{
RBNode
<
E
>
prev
=
(RBNode
<
E
>
)cur.left;
while
(
!
((RBNode
<
E
>
)prev.right).isNull())
{
prev
=
(RBNode
<
E
>
)prev.right;
}
cur.key
=
prev.key;
cur
=
prev;
}
if
(
!
((RBNode
<
E
>
)cur.left).isNull())
{
if
(cur
==
root) {
root
=
cur.left;
((RBNode
<
E
>
)root).color
=
RBNode.BLACK;
return
true
;
}
if
(cur.parent.left
==
cur)
{
cur.parent.left
=
cur.left;
((RBNode
<
E
>
)cur.left).parent
=
cur.parent;
}
else
{
cur.parent.right
=
cur.left;
((RBNode
<
E
>
)cur.left).parent
=
cur.parent;
}
if
(cur.color
==
RBNode.BLACK)
{
((RBNode
<
E
>
)cur.left).color
=
RBNode.BLACK;
}
}
else
if
(
!
((RBNode
<
E
>
)cur.right).isNull())
{
if
(cur
==
root) {
root
=
cur.right;
((RBNode
<
E
>
)root).color
=
RBNode.BLACK;
return
true
;
}
if
(cur.parent.left
==
cur)
{
cur.parent.left
=
cur.right;
((RBNode
<
E
>
)cur.right).parent
=
cur.parent;
}
else
{
cur.parent.right
=
cur.right;
((RBNode
<
E
>
)cur.right).parent
=
cur.parent;
}
if
(cur.color
==
RBNode.BLACK)
{
((RBNode
<
E
>
)cur.right).color
=
RBNode.BLACK;
}
}
else
{
if
(cur
==
root)
{
root
=
null
;
return
true
;
}
RBNode
<
E
>
todo;
if
(cur.parent.left
==
cur)
{
todo
=
newNullNode(cur.parent);
cur.parent.left
=
todo;
}
else
{
todo
=
newNullNode(cur.parent);
cur.parent.right
=
todo;
}
if
(cur.color
==
RBNode.BLACK)
{
//
now todo is a double black node, we will eliminate the double black
fixup_double_black(todo);
}
}
return
true
;
}
@Override
public
E findMax() {
if
(isEmpty())
return
null
;
BSTNode
<
E
>
node
=
root;
while
(
!
((RBNode
<
E
>
)node.right).isNull())
{
node
=
node.right;
}
return
node.key;
}
@Override
public
E findMin() {
if
(isEmpty())
return
null
;
BSTNode
<
E
>
node
=
root;
while
(
!
((RBNode
<
E
>
)node.left).isNull())
{
node
=
node.left;
}
return
node.key;
}
private
final
RBNode
<
E
>
newNullNode(RBNode
<
E
>
p)
{
return
new
RBNode
<
E
>
(p,
null
,RBNode.BLACK);
}
private
final
RBNode
<
E
>
newNormalNode(RBNode
<
E
>
p,E key,
boolean
color)
{
RBNode
<
E
>
node
=
new
RBNode
<
E
>
(p,key,color);
node.left
=
newNullNode(node);
node.right
=
newNullNode(node);
return
node;
}
private
final
void
fixup_double_black(RBNode
<
E
>
cur) {
RBNode
<
E
>
sibling;
RBNode
<
E
>
p;
while
(cur
!=
root)
//
until its parent,parent maybe double black
{
p
=
cur.parent;
if
(p.left
==
cur)
{
sibling
=
(RBNode
<
E
>
)p.right;
if
(sibling.color
==
RBNode.RED)
{
rotate_from_right(p);
p.color
=
RBNode.RED;
sibling.color
=
RBNode.BLACK;
//
actually, p.parent==sibling, remember we have done one rotation
//
this case transformed to another case handled in other place
}
else
{
if
(((RBNode
<
E
>
)sibling.right).color
==
RBNode.RED)
{
rotate_from_right(p);
sibling.color
=
p.color;
//
also, p.parent==sibling, some textbook say here sibling's color can be red while not violate the 3th rule, i don't think so.
p.color
=
RBNode.BLACK;
((RBNode
<
E
>
)sibling.right).color
=
RBNode.BLACK;
//
ok done!
return
;
}
else
if
(((RBNode
<
E
>
)sibling.left).color
==
RBNode.RED)
{
rotate_from_left(sibling);
sibling.color
=
RBNode.RED;
sibling.parent.color
=
RBNode.BLACK;
//
its parent was previously be its left child, remember we have done a left rotation from sibling
//
now transformed to previous case, double black 's sibling(black) have right child colored red
}
else
//
sibling's two children are both black
{
//
re-coloring the sibling and parent
sibling.color
=
RBNode.RED;
if
(p.color
==
RBNode.BLACK)
{
cur
=
p;
//
now the cur node was not double black node ,but p was a double black
}
else
{
p.color
=
RBNode.BLACK;
//
eliminated the double black node
return
;
}
}
}
}
else
{
sibling
=
(RBNode
<
E
>
)p.left;
if
(sibling.color
==
RBNode.RED)
{
rotate_from_left(p);
p.color
=
RBNode.RED;
sibling.color
=
RBNode.BLACK;
//
actually, p.parent==sibling, remember we have done one rotation
//
this case transformed to another case handled in other place
}
else
{
if
(((RBNode
<
E
>
)sibling.left).color
==
RBNode.RED)
{
rotate_from_left(p);
sibling.color
=
p.color;
//
also, p.parent==sibling, some textbook say here sibling's color can be red while not violate the 3th rule, i don't think so.
p.color
=
RBNode.BLACK;
((RBNode
<
E
>
)sibling.left).color
=
RBNode.BLACK;
//
ok done!
return
;
}
else
if
(((RBNode
<
E
>
)sibling.right).color
==
RBNode.RED)
{
rotate_from_right(sibling);
sibling.color
=
RBNode.RED;
sibling.parent.color
=
RBNode.BLACK;
//
its parent was previously be its right child, remember we have done a left rotation from sibling
//
now transformed to previous case, double black 's sibling(black) have right child colored red
}
else
//
sibling's two children are both black
{
//
re-coloring the sibling and parent
sibling.color
=
RBNode.RED;
if
(p.color
==
RBNode.BLACK)
{
cur
=
p;
//
now the cur node was not double black node ,but p was a double black
}
else
{
p.color
=
RBNode.BLACK;
//
eliminated the double black node
return
;
}
}
}
}
}
}
@Override
public
final
void
insert(E ele) {
if
(root
==
null
)
{
root
=
newNormalNode(
null
,ele,RBNode.BLACK);
//
now root's black-height(bh) is 1
return
;
}
RBNode
<
E
>
ret
=
_insert((RBNode