JAVA红黑树
概念:每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色,提高二叉树的查找性能;
特性:
性质1. 节点是红色或黑色。
性质2. 根是黑色。
性质3. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
性能:O(log n)的时间之外,每次插入或删除需要O(log n)的空间。
实现:
JAVAQueue:用linkedlist写的队列
public class JavaQueue {
/**
* @param args
*/
private LinkedList list = new LinkedList();
public void push(Object v) {
list.addFirst(v);
}
public Object pop() {
return list.removeFirst();
}
public Object get() {
return list.removeLast();
}
public boolean isEmpty(){
return list.isEmpty();
}
}
JAVAStack:用linkedlist写的堆栈
import com.sun.xml.internal.bind.v2.schemagen.xmlschema.List;
public class JavaStack {
private LinkedList list = new LinkedList();
public void push(Object v) {
list.addFirst(v);
}
public Object pop(){
return list.removeFirst();
}
public Object top(){
return list.getFirst();
}
public boolean IsNull(){
if(list.size()==0) return true;
else return false;
}
/*public static void main(String[] args) {
// TODO Auto-generated method stub
JavaStack stack=new JavaStack();
for(int i=0;i<10;i++)
{
stack.push(i);
}
System.out.println(stack.top());
stack.pop();
System.out.println(stack.top());
Map map=new HashMap();
A a=new A();
A b=new A();
A c=new A();
int i=0;
map.put(i, a);
map.put(i++, b);
map.put(i++, c);
}
*/
}
TreeNode:定义的节点类
TestRBT类:主要功能实现
import sun.management.counter.Variability;
import com.sun.org.apache.regexp.internal.recompile;
import com.sun.org.apache.xml.internal.security.Init;
public class TestRBT {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// 1.建立一棵树,并进行初始化,也可通过插入节点进行建树
// TreeNode[] node = new TreeNode[23];
// 插入结点操作
TreeNode nil = new TreeNode(null, null, null, -1, 1);//设定哨兵节点
creatTree(nil);// 通过插入结点创建树,并以哨兵节点的父指针指向根节点
showTree(nil.pNode, nil);// 展示插入建树后的结果
deleteTree(nil, 8);// 删除节点,删除的节点也可从外部传入
System.out.println("删除结点后:");
showTree(nil.pNode, nil);// 展示删除树结点的结果
}
public static void initTree(TreeNode node, TreeNode nil) {
//初始化构造树int[] a={1,2,5,7,8,11,14,15,4}
TreeNode tempnode = new TreeNode(nil, nil, nil, -1, 1);
node.leftNode = new TreeNode(nil, nil, node, 2, 0);
node.rightNode = new TreeNode(nil, nil, node, 14, 1);
tempnode = node.leftNode;
tempnode.leftNode = new TreeNode(nil, nil, tempnode, 1, 1);
tempnode.rightNode = new TreeNode(nil, nil, tempnode, 7, 1);
tempnode = tempnode.rightNode;
tempnode.leftNode = new TreeNode(nil, nil, tempnode, 5, 0);
tempnode.rightNode = new TreeNode(nil, nil, tempnode, 8, 0);
tempnode = node.rightNode;
tempnode.rightNode = new TreeNode(nil, nil, tempnode, 15, 0);
/*
* int i = 2; while (i < 23) { if ((i == 2) || (i == 3) || (i == 4) ||
* (i == 6) || (i == 7) || (i == 9) || (i == 11) || (i == 12) || (i ==
* 14) || (i == 17) || (i == 18) || (i == 19) || (i == 20) || (i == 22))
* node[i] = new TreeNode(nil, nil, nil, i, 1); i++; } // 赋值
* node[7].setLeftNode(node[4]); node[7].setRightNode(node[11]);
* node[4].setLeftNode(node[3]); node[4].setRightNode(node[6]);
* node[4].setPNode(node[7]); node[3].setLeftNode(node[2]);
* node[3].setPNode(node[4]); node[2].setPNode(node[3]);
* node[6].setPNode(node[4]);
*
* node[11].setLeftNode(node[9]); node[11].setRightNode(node[18]);
* node[11].setPNode(node[7]);
*
* node[18].setLeftNode(node[14]); node[18].setRightNode(node[19]);
* node[18].setPNode(node[11]);
*
* node[14].setLeftNode(node[12]); node[14].setRightNode(node[17]);
* node[14].setPNode(node[18]);
*
* node[19].setRightNode(node[22]); node[19].setPNode(node[18]);
*
* node[22].setLeftNode(node[20]); node[22].setPNode(node[19]);
*
* node[12].setPNode(node[14]); node[17].setPNode(node[14]);
* node[20].setPNode(node[22]); // show(node);
*
*/
}
public static void showTree(TreeNode node, TreeNode nil) {
// 中序循环遍历树
/*
* JavaStack stack = new JavaStack(); // 将根结点输入栈中 while (node != nil ||
* !stack.IsNull()) { if (node != nil) { stack.push(node); node =
* node.leftNode; } else { TreeNode tempnode = (TreeNode) stack.pop();
* System.out.print(tempnode.key+" " ); if (tempnode.rightNode != nil)
* node = tempnode.rightNode; } }
*/
// 层次遍历,分别打印出树的根结点,不用递归用循环提高效率
JavaQueue queue = new JavaQueue();
queue.push(node);// 将根结点输入栈中
while (!queue.isEmpty()) {//队列不为空则出队列,继续添加新节点
/**/
TreeNode tempnode = (TreeNode) queue.get();
int key = tempnode.key;
StringBuffer str = new StringBuffer();//通过StringBuffer进行输出
str.append("key:" + key);
if (tempnode.color == 0) {
str.append(" color:红色");
} else {
str.append(" color:黑色");
}
if (tempnode.leftNode != nil && tempnode.leftNode != null) {
str.append(" lefttree:" + tempnode.leftNode.key);
queue.push(tempnode.leftNode);
}
if (tempnode.rightNode != nil) {
str.append(" righttree:" + tempnode.rightNode.key);
queue.push(tempnode.rightNode);
}
System.out.println(str.toString());
}
}
public static void leftRotate(TreeNode xnode, TreeNode nil) {
//左旋转的实际为改变节点的前趋后继,三个节点,当前节点,当前节点的右节点,当前节点右节点的左节点
TreeNode yNode = xnode.rightNode;// 设置右孩子为y结点
xnode.rightNode = yNode.leftNode;
if (yNode.leftNode != nil)
yNode.leftNode.pNode = xnode;
yNode.pNode = xnode.pNode;
if (xnode.pNode == nil) {
nil.pNode = yNode;
} else if (xnode == xnode.pNode.leftNode) {
xnode.pNode.leftNode = yNode;
} else {
xnode.pNode.rightNode = yNode;
}
yNode.leftNode = xnode;
xnode.pNode = yNode;
}
public static void rightRotate(TreeNode xnode, TreeNode nil) {
TreeNode yNode = xnode.leftNode;// 设置左孩子为y结点
xnode.leftNode = yNode.rightNode;
if (yNode.rightNode != nil) {
yNode.rightNode.pNode = xnode;
}
yNode.pNode = xnode.pNode;
if (xnode.pNode == nil) {
nil.pNode = yNode;
} else if (xnode == xnode.pNode.rightNode) {
xnode.pNode.rightNode = yNode;
} else {
xnode.pNode.leftNode = yNode;
}
yNode.rightNode = xnode;
xnode.pNode = yNode;
}
public static void InsertTreeNode(int i, TreeNode nil) {
TreeNode newnode = new TreeNode(nil, nil, nil, i, 0);// 设置新插入结点初始值为i
TreeNode tempnode = new TreeNode(nil, nil, nil, -1, 0);// 设置比较结点的父结点
TreeNode recnode = new TreeNode(nil, nil, nil, -1, 0);// 设置一个循环树结点
// 执行查找过程,找到相应的位置并进行插入,随后进行红黑性质的插入调整
recnode = nil.pNode;
if (recnode == null) {
nil.pNode = newnode;
newnode.color = 1;
} else {
while (recnode != nil) {
tempnode = recnode;
if (i < recnode.key) {
recnode = recnode.leftNode;
} else {
recnode = recnode.rightNode;
}
}
newnode.pNode = tempnode;
if (newnode.key < tempnode.key) {
tempnode.leftNode = newnode;
} else {
tempnode.rightNode = newnode;
}
// 执行修补程序
InsertTreeNodeFixup(nil, newnode);
}
}
public static void InsertTreeNodeFixup(TreeNode nil, TreeNode newnode) {
TreeNode tempnode = new TreeNode(nil, nil, nil, -1, 0);
/*执行插入主要解决红红冲突,具体情况有三种,注意插入的结点默认均为红色
* 1.newnode 的叔叔为红,即将其父,叔结点均置为黑
* 2.newnode 的叔叔是黑,newnode为父结点的右孩子
* 3.newnode 的叔叔是黑,newnode为父结点的左孩子
* 2,3的解决办法是先进行一次相应方向的旋转(左子树即左转,右子树即右转),然后将newnode设为祖父结点,
* 进行相应的反方向转动,最后设置根结点值为黑色
* 插入操作可通过两次旋转彻底解决平衡问题
*/
while (newnode.pNode.color == 0) {
if (newnode.pNode == newnode.pNode.pNode.leftNode) {
tempnode = newnode.pNode.pNode.rightNode;// 叔父结点为爷爷的左子树
if (tempnode.color == 0) {// 叔父结点为红
newnode.pNode.color = 1;
tempnode.color = 1;
newnode.pNode.pNode.color = 0;
newnode = newnode.pNode.pNode;
} else {
if (newnode == newnode.pNode.rightNode)// 叔父结点为黑并为其父爷点的左子树
{
newnode = newnode.pNode;
leftRotate(newnode, nil);
}
newnode.pNode.color = 1;
newnode.pNode.pNode.color = 0;
rightRotate(newnode.pNode.pNode, nil);
}
} else {
tempnode = newnode.pNode.pNode.leftNode;// 叔父结点为爷爷的右子树
if (tempnode.color == 0) {// 叔父结点为红
newnode.pNode.color = 1;
tempnode.color = 1;
newnode.pNode.pNode.color = 0;
newnode = newnode.pNode.pNode;
} else // 叔父结点为黑并为其父爷点的左子树
{
if (newnode == newnode.pNode.leftNode) {
newnode = newnode.pNode;
rightRotate(newnode, nil);
}
newnode.pNode.color = 1;
newnode.pNode.pNode.color = 0;
leftRotate(newnode.pNode.pNode, nil);
}
}
}
nil.pNode.color = 1;
}
public static void creatTree(TreeNode nil) {
// 新建NIL[T]结点
// int number = Integer.parseInt(JOptionPane.showInputDialog("请输入个数:"));
int[] number = new int[] { 1, 2, 5, 7, 8, 11, 14, 15, 4 };
// int[] number = new int[] { 8,11,17,15,6,1,22,25,27 };
for (int i = 0; i < number.length; i++) {
// int inputValue = Integer.parseInt(JOptionPane
// .showInputDialog("请输入树节点值:"));
int inputValue = number[i];
InsertTreeNode(inputValue, nil);
}
}
public static void deleteTree(TreeNode nil, int i) {
/*删除结点主要考虑三个问题:
* 1.删除的为叶子节点,即左右子树为空
* 2.删除的为带一棵子树的结点
* 前面两种情况可以合并讨论,都是直接让父结点指向孩子结点或空节点(左右子树为空时),删除后设置
* 旋转结点,进行修复
* 3.删除的为有左右子树的结点,需要取得其后继结点,作为新结点
*
*
*
*
*
* */
// 查找到删除节点,从根结点开始循环遍历
TreeNode zNode = new TreeNode(nil, nil, nil, i, 1);
TreeNode xNode = new TreeNode(nil, nil, nil, -1, 1);
TreeNode tempNode = nil.pNode;// 设置根结点
TreeNode rootnode= new TreeNode(nil, nil, nil, -1, 1);
boolean mark = false;// 查找对象结点
while (tempNode != nil && mark == false) {
if (zNode.key < tempNode.key) {
tempNode = tempNode.leftNode;
} else if (zNode.key > tempNode.key) {
tempNode = tempNode.rightNode;
} else {
zNode = tempNode;
mark = true;
}
}
// zNode即为当前节点,进行删除操作
TreeNode yNode = new TreeNode(nil, nil, nil, -1, 1);//y结点用于指示被删除节点
if ((zNode.leftNode == nil) || (zNode.rightNode == nil)) {
yNode = zNode;// 用yNode指向将被删除的结点
} else {
yNode = lookAfterNode(nil, zNode);// 寻找后继节点
}
// 进行删除,通过后继与父母结点之间建立双向关系进行删除
if (yNode.leftNode != nil) {
xNode = yNode.leftNode;
} else {
xNode = yNode.rightNode;
}
if ((zNode.leftNode == nil) && (zNode.rightNode == nil)) {
rootnode=xNode.pNode;//此时指向空值时,nil的父母节点会改变,所以在此保留根结点,最后恢复时可用
}
xNode.pNode = yNode.pNode;
// //////////////////////////////////////////
if (yNode.pNode == nil) {
nil.pNode = xNode;
} else if (yNode == yNode.pNode.leftNode) {
yNode.pNode.leftNode = xNode;
} else {
yNode.pNode.rightNode = xNode;
}
if (yNode != zNode) {
zNode.key = yNode.key;
}
if (yNode.color == 1) {//解决黑黑冲突,如果为红则不需要改变
deleteTreeFixUp(nil, xNode);
}
nil.pNode=rootnode;//还原根结点为nit的父母结点
}
public static TreeNode lookAfterNode(TreeNode nil, TreeNode node) {
TreeNode returnNode = new TreeNode(nil, nil, nil, -1, 0);
if (node.rightNode != nil) {
returnNode = node.rightNode;
while (returnNode.leftNode != nil) {
returnNode = returnNode.leftNode;
}
return returnNode;
}
returnNode = node.pNode;
while (returnNode != nil && node == returnNode.rightNode) {
node = returnNode;
returnNode = node.pNode;
}
return returnNode;
}
public static void deleteTreeFixUp(TreeNode nil, TreeNode xNode) {
/* 删除修复:
* 1.x的兄弟w是红色的
* 2.x的兄弟w是黑色的,而且w的两个孩子都是黑色的
* 3.x的兄弟w是黑色的,而且w的左孩子为红,右孩子为黑
* 4.x的兄弟w是黑色的,而且w的左孩子为黑,右孩子为红
* */
TreeNode adjustNode = new TreeNode(nil, nil, nil, -1, 1);
while (xNode != nil.pNode && xNode.color == 1) {
if (xNode == xNode.pNode.leftNode) {
adjustNode = xNode.pNode.rightNode;
if (adjustNode.color == 0) {
adjustNode.color = 1;
xNode.pNode.color = 0;
leftRotate(xNode.pNode, nil);
adjustNode = xNode.pNode.rightNode;
}
if (adjustNode.leftNode.color == 1
&& adjustNode.rightNode.color == 1) {
adjustNode.color = 0;
xNode = xNode.pNode;
} else if (adjustNode.rightNode.color == 1) {
adjustNode.leftNode.color = 1;
adjustNode.color = 0;
rightRotate(adjustNode, nil);
adjustNode = xNode.pNode.rightNode;
}
adjustNode.color = adjustNode.pNode.color;
adjustNode.pNode.color = 1;
adjustNode.rightNode.color = 1;
leftRotate(xNode.pNode, nil);
xNode = nil.pNode;
} else {
adjustNode = xNode.pNode.leftNode;
if (adjustNode.color == 0) {
adjustNode.color = 1;
xNode.pNode.color = 0;
rightRotate(xNode.pNode, nil);
adjustNode = xNode.pNode.leftNode;
}
if (adjustNode.rightNode.color == 1
&& adjustNode.leftNode.color == 1) {
adjustNode.color = 0;
xNode = xNode.pNode;
} else if (adjustNode.leftNode.color == 1) {
adjustNode.rightNode.color = 1;
adjustNode.color = 0;
leftRotate(adjustNode, nil);
adjustNode = xNode.pNode.leftNode;
}
adjustNode.color = adjustNode.pNode.color;
adjustNode.pNode.color = 1;
adjustNode.leftNode.color = 1;
rightRotate(xNode.pNode, nil);
xNode = nil.pNode;
}
}
xNode.color = 1;
}
}