我正在尝试实现RedBlack树插入方法,但它无法按预期工作。这是源代码。
插入方法:
void insert( int key ) { root = insert( null, root, key ); root.color = BLACK; }
private Node insert( Node parent, Node root, int key )
{
//STEP 1 : Classic BST insertion
if ( root == null )
return ( new Node( parent, key, RED ) );
boolean isLeft;
if ( key < root.key )
{
root.left = insert( root, root.left, key);
isLeft = true;
}
else
{
root.right = insert( root, root.right, key);
isLeft = false;
}
//STEP2: Self balancing the tree.
if ( isLeft )
{
if ( root.color == RED && root.left.color == RED )
{
Node sibling = findSibling( root );
if ( ! isRed( sibling ) )
{
if ( isLeftChild( root ) )
{
return rightRotate( root, true );
}
else
{
//recolore( root );
}
}
}
}
else
{
// mirror case
// yet to do
}
return root;
}
RightRotate方法+其他使用的方法:
private Node rightRotate( Node newRoot, boolean changeColor )
{
Node oldRoot = newRoot.parent;
oldRoot.left = newRoot.right;
newRoot.right = oldRoot;
newRoot.parent = oldRoot.parent;
oldRoot.parent = newRoot;
if ( changeColor )
{
root.color = BLACK;
root.parent.color = RED;
}
return newRoot;
}
private Node findSibling( Node root )
{
Node parent = root.parent;
if ( parent.left == root )
return parent.right;
return parent.left;
}
private boolean isRed( Node root )
{
if ( root == null )
return false;
return root.color == RED;
}
private boolean isLeftChild( Node root )
{
if ( root.parent == null )
return false;
if ( root.parent.left == root )
return true;
return false;
}
树的主要+预先打印:
void preOrder() { preOrder( root ); }
private void preOrder( Node root )
{
if ( root != null )
{
System.out.print( " | " + ( root.color ? "RED" : "BLACK" ) + " " + root.key + " |" );
preOrder( root.left );
preOrder( root.right );
}
}
}
class Main
{
public static void main( String[] args )
{
RedBlackBST tree = new RedBlackBST();
tree.insert( 3 );
tree.insert( 2 );
tree.insert( 1 );
tree.preOrder();
}
}
此实现尚未完成,仅适用于左左侧情况(如主方法3,2,1),这意味着我必须进行正确的旋转。
预期输出应为:
| BLACK 2 | | RED 1 | | RED 3 |
而不是这个输出我得
| BLACK 3 | | BLACK 2 | | RED 1 | | BLACK 3 | | BLACK 2 | | RED 1 | ... // infinity loop
有谁能告诉我在哪里犯错误?显然我不想发布整个代码,而只是建议如何解决这个问题,以及为什么它不起作用。
答案 0 :(得分:0)
您应该首先执行一个二进制搜索树插入操作,然后修复插入操作,因为它现在可能不平衡。重新平衡时应考虑4种不同的情况,以下代码显示了它们。这是C#中的代码(应该很容易将其转换为java)。在下面的代码中,T1是树节点中键的类型,而T2是树节点中值的类型。该实现是通用的。
public RedBlackTreeNode<T1, T2> Insert(RedBlackTreeNode<T1, T2> root, RedBlackTreeNode<T1, T2> newNode)
{
root = Insert_BST(root, newNode); /* is normal bst insert.*/
Insert_Repair(root, newNode);
root = newNode;
while (root.Parent != null)
{
root = root.Parent;
}
return root;
}
private void Insert_Repair(RedBlackTreeNode<T1, T2> root, RedBlackTreeNode<T1, T2> newNode)
{
if (newNode.Parent == null && newNode.Color == Color.Red) /* Property: the root is black. */
{
newNode.FlipColor();
}
else if (newNode.Parent != null && newNode.Parent.Color == Color.Red) /* If this holds it means that both the new node and its parent are red, and in a red-black tree this is not allowed. Children of a red node should be black.*/
{
var uncle = newNode.GetUncle();
if (uncle != null && uncle.Color == Color.Red) /* Both the parent and uncle of the new node are red. Note that a null uncle is considered black. */
{
newNode.Parent.Color = Color.Black;
uncle.Color = Color.Black;
newNode.GetGrandParent().Color = Color.Red;
Insert_Repair(root, newNode.GetGrandParent()); /* Repeat repair on the grandparent, as by the re-coloring the previous layers could have been messed up. */
}
else if (uncle == null || uncle.Color == Color.Black)
{`enter code here`
if (newNode.FormsTriangle() && newNode.IsLeftChild())
{
RotateRight(newNode.Parent);
newNode = newNode.RightChild; /* After rotation new node has become the parent of its former parent.*/
/* Triangle is transformed to a line.*/
}
else if (newNode.FormsTriangle() && newNode.IsRightChild())
{
RotateLeft(newNode.Parent);
newNode = newNode.LeftChild; /* After rotation new node has become the parent of its former parent.*/
/* Triangle is transformed to a line.*/
}
/* When reaching at this point, we might or might not have gone through above two triangle forms, as the alignment could have already been a line.*/
var grandParent = newNode.GetGrandParent();
if (newNode.IsRightChild())
{
RotateLeft(grandParent);
}
else if (newNode.IsLeftChild())
{
RotateRight(grandParent);
}
newNode.Parent.Color = Color.Black;
if (grandParent != null)
grandParent.Color = Color.Red;
}
}
}