二叉树与红黑树的java实现
Posted 李润
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树与红黑树的java实现相关的知识,希望对你有一定的参考价值。
二叉树的java实现
public class BinaryTree {
/**
* 根节点
*/
private static Node root;
static class Node {
int key;
Node left, right, parent;
public Node(int key) {
this.key = key;
}
}
public BinaryTree(int key) {
root = new Node(key);
}
/**
* 中序遍历
*
* @param node 根节点
*/
public void inOrderTreeWalk(Node node) {
if (node != null) {
inOrderTreeWalk(node.left);
System.out.print(node.key + ",");
inOrderTreeWalk(node.right);
}
}
/**
* 查找
*
* @param node 根节点
* @param key 查找值
* @return
*/
public Node treeSearch(Node node, int key) {
while (node != null && key != node.key) {
if (key < node.key) {
node = node.left;
} else {
node = node.right;
}
}
return node;
}
/**
* 最小值
*
* @param node 根节点
* @return
*/
public Node treeMinimum(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}
/**
* 最大值
*
* @param node 根节点
* @return
*/
public Node treeMaximum(Node node) {
while (node.right != null) {
node = node.right;
}
return node;
}
/**
* 前驱
*
* @param node 根节点
* @return
*/
public Node treePredecessor(Node node) {
// 如果存在左子树,返回左子树的最大值
if (node.left != null) {
return treeMaximum(node.left);
}
Node y = node.parent;
// 当不存在左子树时,返回最低祖先节点
while (y != null && node == y.left) {
node = y;
y = y.parent;
}
return y;
}
/**
* 后继
*
* @param node 根节点
* @return
*/
public Node treeSuccessor(Node node) {
// 如果存在右子树,返回右子树的最小值
if (node.right != null) {
return treeMinimum(node.right);
}
Node y = node.parent;
// 当不存在右子树时,返回最低祖先节点
while (y != null && node == y.right) {
node = y;
y = y.parent;
}
return y;
}
/**
* 插入
*
* @param key 插入节点的关键值
*/
public void treeInsert(int key) {
// 创建插入节点
Node node = new Node(key);
// 定义插入节点的父节点变量
Node y = null;
// 定义临时变量存根节点
Node x = root;
// 在根节点的左、右子树中查找插入位置
while (x != null) {
y = x;
if (key < x.key) {
x = x.left;
} else {
x = x.right;
}
}
node.parent = y;
if (y == null) {
root = node;
} else if (key < y.key) {
y.left = node;
} else {
y.right = node;
}
}
/**
* 删除
*
* @param node 删除节点
* @return
*/
public Node treeDelete(Node node) {
// 定义临时变量存删除节点或后继节点
Node y;
// 当删除节点至多有一个孩子时
if (node.left == null || node.right == null) {
y = node;
} else {// 当删除节点有两个孩子时,y存后继节点
y = treeSuccessor(node);
}
// 定义临时变量存删除节点的孩子节点
Node x;
if (y.left != null) {
x = y.left;
} else {
x = y.right;
}
if (x != null) {
x.parent = y.parent;
}
if (y.parent == null) {
root = x;
} else if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
// 当y为后继节点时,将y的关键值赋给删除节点
if (y != node) {
node.key = y.key;
}
return y;
}
}
红黑树的java实现(备注:中序遍历、查找、最大、最小、前驱、后继与二叉树基本一致)
public class RBTree {
/**
* 根节点
*/
private static Node root;
/**
* nil节点是红黑树的叶子节点不同于二叉树的叶子节点
* 颜色为黑色,key、left、right、parent可以是任意允许的值
* 这里key设置为0,left、right、parent为null
*/
private Node nil = new Node(true);
static class Node {
int key;
Node left, right, parent;
boolean color;// true黑,false红
public Node(int key) {
this.key = key;
}
public Node(boolean color) {
this.color = color;
}
public boolean equals(Node node) {
return this.key == node.key;
}
}
public RBTree(int key) {
root = new Node(key);
}
/**
* 中序遍历
*
* @param node 根节点
*/
public void inOrderTreeWalk(Node node) {
if (node != null && !node.equals(nil)) {
inOrderTreeWalk(node.left);
System.out.print((node.color == true ? "黑" : "红") + node.key + ",");
inOrderTreeWalk(node.right);
}
}
/**
* 查找
*
* @param node 根节点
* @param key 查找值
* @return
*/
public Node treeSearch(Node node, int key) {
while (node != null && key != node.key) {
if (key < node.key) {
node = node.left;
} else {
node = node.right;
}
}
return node;
}
/**
* 最小值
*
* @param node 根节点
* @return
*/
public Node treeMinimum(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}
/**
* 最大值
*
* @param node 根节点
* @return
*/
public Node treeMaximum(Node node) {
while (node.right != null) {
node = node.right;
}
return node;
}
/**
* 前驱
*
* @param node 根节点
* @return
*/
public Node treePredecessor(Node node) {
// 如果存在左子树,返回左子树的最大值
if (node.left != null) {
return treeMaximum(node.left);
}
Node y = node.parent;
// 当不存在左子树时,返回最低祖先节点
while (y != null && node == y.left) {
node = y;
y = y.parent;
}
return y;
}
/**
* 后继
*
* @param node 根节点
* @return
*/
public Node treeSuccessor(Node node) {
// 如果存在右子树,返回右子树的最小值
if (node.right != null) {
return treeMinimum(node.right);
}
Node y = node.parent;
// 当不存在右子树时,返回最低祖先节点
while (y != null && node == y.right) {
node = y;
y = y.parent;
}
return y;
}
/**
* 左旋(node节点必有右孩子)
*
* @param node
*/
public void leftTotate(Node node) {
Node y = node.right;
node.right = y.left;
if (y.left != null)
y.left.parent = node;
y.parent = node.parent;
if (node.parent == null) {
root = y;
} else if (node == node.parent.left) {
node.parent.left = y;
} else {
node.parent.right = y;
}
node.parent = y;
y.left = node;
}
/**
* 右旋(node节点必有左孩子)
*
* @param node
*/
public void rightTotate(Node node) {
Node y = node.left;
node.left = y.right;
if (y.right != null)
y.right.parent = node;
y.parent = node.parent;
if (node.parent == null) {
root = y;
} else if (node == node.parent.left) {
node.parent.left = y;
} else {
node.parent.right = y;
}
node.parent = y;
y.right = node;
}
/**
* 插入
*
* @param key 插入节点的关键值
*/
public void RBTreeInsert(int key) {
// 创建插入节点
Node node = new Node(key);
// 定义插入节点的父节点变量
Node y = null;
// 定义临时变量存根节点
Node x = root;
// 在根节点的左、右子树中查找插入位置
while (x != null) {
y = x;
if (key < x.key) {
x = x.left;
} else {
x = x.right;
}
}
node.parent = y;
if (y == null) {
root = node;
} else if (key < y.key) {
y.left = node;
} else {
y.right = node;
}
RBTreeInsertFixup(node);
}
/**
* 插入后修复
*
* @param node 插入节点
*/
public void RBTreeInsertFixup(Node node) {
// 当插入节点的父节点为红色时,执行循环
while (node.parent != null && !node.parent.color && node.parent.parent != null) {
// 当插入节点的父节点为其爷爷节点的左孩子时
if (node.parent == node.parent.parent.left) {
// 定义y存叔叔节点
Node y = node.parent.parent.right;
// 如果叔叔节点为红色,将父节点与叔叔节点变成黑色,爷爷节点变成红色,将插入节点升级为爷爷节点
if (y != null && !y.color) {
node.parent.color = true;
y.color = true;
node.parent.parent.color = false;
node = node.parent.parent;
} else if (node == node.parent.right) {//如果叔叔节点为黑色,插入节点是父节点的右孩子,将插入节点升级为父节点,左旋插入节点
node = node.parent;
leftTotate(node);
} else {//如果叔叔节点为黑色,插入节点是父节点的左孩子,将父节点变成黑色,爷爷节点变成红色,右旋爷爷节点
node.parent.color = true;
node.parent.parent.color = false;
rightTotate(node.parent.parent);
}
} else {// 当插入节点的父节点为其爷爷节点的右孩子时
// 定义y存叔叔节点
Node y = node.parent.parent.left;
// 如果叔叔节点为红色,将父节点与叔叔节点变成黑色,爷爷节点变成红色,将插入节点升级为爷爷节点
if (y != null && !y.color) {
node.parent.color = true;
y.color = true;
node.parent.parent.color = false;
node = node.parent.parent;
} else if (node == node.parent.left) {//如果叔叔节点为黑色,插入节点是父节点的左孩子,将插入节点升级为父节点,右旋插入节点
node = node.parent;
rightTotate(node);
} else {//如果叔叔节点为黑色,插入节点是父节点的右孩子,将父节点变成黑色,爷爷节点变成红色,左旋爷爷节点
node.parent.color = true;
node.parent.parent.color = false;
leftTotate(node.parent.parent);
}
}
}
// 将根节点变成黑色
if (root.parent != null) {
root = root.parent;
}
root.color = true;
}
/**
* 删除
*
* @param node 删除节点
* @return
*/
public Node RBTreeDelete(Node node) {
// 定义临时变量存删除节点或后继节点
Node y;
// 当删除节点至多有一个孩子时
if (node.left == null || node.right == null) {
y = node;
} else {// 当删除节点有两个孩子时,y存后继节点
y = treeSuccessor(node);
}
// 定义临时变量存删除节点的孩子节点
Node x;
if (y.left != null) {
x = y.left;
} else {
x = y.right;
}
if (x != null) {
x.parent = y.parent;
} else {
x = nil;
x.parent = y.parent;
}
if (y.parent == null) {
root = x;
} else if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
// 当y为后继节点时,将y的关键值赋给删除节点
if (y != node) {
node.key = y.key;
}
// 当y为黑色时,需要修复红黑树
if (y.color) {
RBTreeDeleteFixup(x);
}
return y;
}
/**
* 删除后修复
*
* @param node 删除节点的孩子节点
*/
public void RBTreeDeleteFixup(Node node) {
// 当node不等于根节点并且为黑色时,执行循环
while (node != root && (node == nil || node.color)) {
// 如果node节点为父节点的左孩子
if (node == node.parent.left) {
// 定义w存兄弟节点
Node w = node.parent.right;
// 当兄弟节点为红色时,将兄弟节点变成黑色,父节点变成红色,左旋父节点,更新兄弟节点
if (!w.color) {
w.color = true;
node.parent.color = false;
leftTotate(node.parent);
w = node.parent.right;
} else if (w.left.color && w.right.color) {//当兄弟节点为黑色且其两个孩子都为黑色时,将兄弟节点变成红色,将node节点升级为父节点
w.color = false;
node = node.parent;
} else if (w.right.color) {//当兄弟节点为黑色且其左孩子为红色、其右孩子为黑色时,将其左孩子变成黑色、兄弟节点变成红色,右旋兄弟节点,更新兄弟节点
w.left.color = true;
w.color = false;
rightTotate(w);
w = node.parent.right;
} else {//当兄弟节点为黑色且其右孩子为红色时,将父节点的颜色赋给兄弟节点,父节点变成黑色,兄弟节点的右孩子变成黑色,左旋父节点
w.color = node.parent.color;
node.parent.color = true;
w.right.color = true;
leftTotate(node.parent);
// 将根节点赋给node
if (root.parent != null) {
root = root.parent;
}
node = root;
}
} else {// 如果node节点为父节点的右孩子
// 定义w存兄弟节点
Node w = node.parent.left;
// 当兄弟节点为红色时,将兄弟节点变成黑色,父节点变成红色,右旋父节点,更新兄弟节点
if (!w.color) {
w.color = true;
node.parent.color = false;
rightTotate(node.parent);
w = node.parent.left;
} else if (w.left.color && w.right.color) {//当兄弟节点为黑色且其两个孩子都为黑色时,将兄弟节点变成红色,将node节点升级为父节点
w.color = false;
node = node.parent;
} else if (w.left.color) {//当兄弟节点为黑色且其左孩子为黑色、其右孩子为红色时,将其右孩子变成黑色、兄弟节点变成红色,左旋兄弟节点,更新兄弟节点
w.right.color = true;
w.color = false;
leftTotate(w);
w = node.parent.left;
} else {//当兄弟节点为黑色且其左孩子为红色时,将父节点的颜色赋给兄弟节点,父节点变成黑色,兄弟节点的左孩子变成黑色,右旋父节点
w.color = node.parent.color;
node.parent.color = true;
w.left.color = true;
rightTotate(node.parent);
// 将根节点赋给node
if (root.parent != null) {
root = root.parent;
}
node = root;
}
}
}
// 将node节点变成黑色
node.color = true;
}
public static void main(String[] args) {
int[] arr = { 21, 3, 6, 7, 12, 25, 17, 8, 15 };
RBTree rb = new RBTree(21);
for (int i = 1; i < arr.length; i++) {
rb.RBTreeInsert(arr[i]);
}
rb.inOrderTreeWalk(root);
rb.RBTreeDelete(rb.treeSearch(root, 21));
System.out.println();
rb.inOrderTreeWalk(root);
}
}
以上是关于二叉树与红黑树的java实现的主要内容,如果未能解决你的问题,请参考以下文章