首先定义一颗树:
/**
* 红黑树
* @param <K>
* @param <V>
*
* 红黑树的特性:
* 1. 根节点必须是黑色
* 2. 叶子节点(NIL)必须是黑色
* 3. 从根节点到叶子节点的黑色节点的数量一致
* 4. 不能有两个相邻的红色节点
* 5. 红黑树要么是红色/要么是黑色
* 6. 新增节点一般是红色 (为红色不一定会破坏红黑树的特性 为黑色则一定会破坏红黑数的特性)
*/
public class RBTree <K extends Comparable,V>{
private Boolean BLACK=false;
private Boolean RED=true;
private RBNode root; // 根节点
static class RBNode<K extends Comparable,V>{
private RBNode left;
private RBNode right;
private RBNode parent;
private K key;
private V value;
private Boolean color;
}
定义基础操作方法:
/**
* 变色
*/
private void setColor(RBNode node,Boolean color){
if(node == null){
return;
}
node.setColor(color);
}
/**
* 获取父级节点
* @param node
* @return
*/
private RBNode getParent(RBNode node){
if(node == null){
return null;
}
return node.getParent();
}
/**
* 是否是红色
* @param node
* @return
*/
private Boolean isRed(RBNode node){
if(node == null){
return false;
}
return node.getColor()==RED;
}
/**
* 中序遍历
*/
public void print(){
RBNode node = this.root;
print(root);
System.out.println("root: "+node.getKey());
}
private void print(RBNode root){
if(root ==null){
return ;
}
print(root.left);
String color=root.getColor()?"红色":"黑色";
System.out.println("key: "+ root.getKey()+" value: "+ root.getValue()+" color: "+ color);
print(root.right);
}
定义左旋右旋:
左旋: 将右子节点的左子节点变为右子节点,将原来的右子节点指向x的父级节点。
右旋:将左子节点的右子节点变为左子节点,将原来的左子节点指向x的父级节点
/**
* 左旋
* 1. 找到node节点的right节点,先将y的left节点变为x的right节点,不为空的话将parent指向x;
* 2. 将y的父级指向x的父级 将x在父级的位置指向y
*/
private void leftRotate(RBNode x){
RBNode y = x.right;
x.right = y.left;
if(y.left !=null){
y.left.parent = x;
}
// 获取x的父级节点 将y的父级指向x的父级节点
RBNode parent = getParent(x);
if(parent !=null){
y.parent = parent;
if(x == parent.left){
parent.left = y;
}else{
parent.right = y;
}
}else{
// 表示x是root节点 直接赋值y
this.root = y;
y.parent = null;
}
x.parent = y;
y.left = x;
}
/**
* 右旋
* 1. 找到node节点的right节点,先将y的left节点变为x的right节点,不为空的话将parent指向x;
* 2. 将y的父级指向x的父级 将x在父级的位置指向y
*/
private void rightRotate(RBNode x){
RBNode y = x.left;
x.left = y.right;
if(y.right !=null){
y.right.parent = x;
}
// 获取x的父级节点 将y的父级指向x的父级节点
RBNode parent = getParent(x);
if(parent !=null){
y.parent = parent;
if(x == parent.left){
parent.left = y;
}else{
parent.right = y;
}
}else{
// 表示x是root节点 直接赋值y
this.root = y;
y.parent = null;
}
x.parent = y;
y.right = x;
}
定义插入,及插入后调整方法:
/**
* 对外insert接口
* @param key
* @param value
*/
public void insert(K key,V value){
RBNode node = new RBNode<>();
node.setColor(RED);
node.setKey(key);
node.setValue(value);
insert(node);
}
/**
* 插入元素 先找到parent
* @param node
*/
private void insert(RBNode node){
RBNode parent= null;
RBNode root = this.root;
while(root !=null){
parent = root;
int tem = node.getKey().compareTo(root.getKey());
if(tem > 0){
root = root.right;
}else if(tem == 0){
root.setValue(node.getValue());
return;
}else{
root = root.left;
}
}
if(parent ==null){
this.root = node;
}else{
node.setParent(parent);
int tem = node.getKey().compareTo(parent.getKey());
if(tem > 0){
parent.right = node;
}else{
parent.left = node;
}
}
ficUp(node);
}
/**
* 调整符合红黑树特性的操作
* 情况分为:
* 1.root节点为空 ,插入后将root节点班委黑色。
* 2. 插入节点的父级节点为黑色 不违反红黑树特性 不做调整
* 3. 插入节点已存在 insert中已覆盖
* 4. 插入节点的父级节点为红色:{
* 1. 如果叔叔级节点为红色 为双红 将父级节点和叔叔级节点变为黑色,将爷爷级节点变为红色 以爷爷节点进行再次处理
* 2. 如果叔叔级节点不存在或为黑色:{
* 1. 父级节点在爷爷级节点的left,插入节点在父级节点的left 为(LL)双红 父级变为黑色,爷爷变为红色。 以爷爷节点进行右旋
* 2. 插入节点在父级的右侧,为(LR) 双红, 以父级节点进行左旋 变为(LL双红)
* 3. 父级节点在爷爷级节点的右侧,插入节点在父级节点的right 为(RR)双红 父级变为黑色,爷爷变为红色。 以爷爷节点进行左旋
* 4. 插入节点在父级的左侧 为(RL)双红 , 以父级节点进行右旋 变为(RR)双红
* }
* }
*/
private void ficUp(RBNode node){
this.root.setColor(BLACK);
RBNode parent = getParent(node);
RBNode gParent = getParent(parent);
if(parent !=null && isRed(parent)){
RBNode uncle = null;
if(gParent.left == parent){
uncle = gParent.right;
}else{
uncle = gParent.left;
}
if(uncle != null && isRed(uncle)){
parent.setColor(BLACK);
uncle.setColor(BLACK);
gParent.setColor(RED);
ficUp(gParent);
return;
}else{
if(parent == gParent.left){
if(parent.left == node){
parent.setColor(BLACK);
gParent.setColor(RED);
rightRotate(gParent);
}else{
leftRotate(parent);
ficUp(parent);
return;
}
}else{
if(parent.left == node){
rightRotate(parent);
ficUp(parent);
return;
}else{
parent.setColor(BLACK);
gParent.setColor(RED);
leftRotate(gParent);
}
}
}
}
}
完整代码如下:
import com.sun.org.apache.xpath.internal.operations.Bool;
import java.util.Collections;
import java.util.TreeMap;
/**
* 红黑树
* @param <K>
* @param <V>
*
* 红黑树的特性:
* 1. 根节点必须是黑色
* 2. 叶子节点(NIL)必须是黑色
* 3. 从根节点到叶子节点的黑色节点的数量一致
* 4. 不能有两个相邻的红色节点
* 5. 红黑树要么是红色/要么是黑色
* 6. 新增节点一般是红色 (为红色不一定会破坏红黑树的特性 为黑色则一定会破坏红黑数的特性)
*/
public class RBTree <K extends Comparable,V>{
private Boolean BLACK=false;
private Boolean RED=true;
private RBNode root; // 根节点
static class RBNode<K extends Comparable,V>{
private RBNode left;
private RBNode right;
private RBNode parent;
private K key;
private V value;
private Boolean color;
public RBNode getLeft() {
return left;
}
public void setLeft(RBNode left) {
this.left = left;
}
public RBNode getRight() {
return right;
}
public void setRight(RBNode right) {
this.right = right;
}
public RBNode getParent() {
return parent;
}
public void setParent(RBNode parent) {
this.parent = parent;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Boolean getColor() {
return color;
}
public void setColor(Boolean color) {
this.color = color;
}
public RBNode() {
}
}
/**
* 变色
*/
private void setColor(RBNode node,Boolean color){
if(node == null){
return;
}
node.setColor(color);
}
/**
* 获取父级节点
* @param node
* @return
*/
private RBNode getParent(RBNode node){
if(node == null){
return null;
}
return node.getParent();
}
/**
* 左旋
* 1. 找到node节点的right节点,先将y的left节点变为x的right节点,不为空的话将parent指向x;
* 2. 将y的父级指向x的父级 将x在父级的位置指向y
*/
private void leftRotate(RBNode x){
RBNode y = x.right;
x.right = y.left;
if(y.left !=null){
y.left.parent = x;
}
// 获取x的父级节点 将y的父级指向x的父级节点
RBNode parent = getParent(x);
if(parent !=null){
y.parent = parent;
if(x == parent.left){
parent.left = y;
}else{
parent.right = y;
}
}else{
// 表示x是root节点 直接赋值y
this.root = y;
y.parent = null;
}
x.parent = y;
y.left = x;
}
/**
* 右旋
* 1. 找到node节点的right节点,先将y的left节点变为x的right节点,不为空的话将parent指向x;
* 2. 将y的父级指向x的父级 将x在父级的位置指向y
*/
private void rightRotate(RBNode x){
RBNode y = x.left;
x.left = y.right;
if(y.right !=null){
y.right.parent = x;
}
// 获取x的父级节点 将y的父级指向x的父级节点
RBNode parent = getParent(x);
if(parent !=null){
y.parent = parent;
if(x == parent.left){
parent.left = y;
}else{
parent.right = y;
}
}else{
// 表示x是root节点 直接赋值y
this.root = y;
y.parent = null;
}
x.parent = y;
y.right = x;
}
/**
* 是否是红色
* @param node
* @return
*/
private Boolean isRed(RBNode node){
if(node == null){
return false;
}
return node.getColor()==RED;
}
/**
* 对外insert接口
* @param key
* @param value
*/
public void insert(K key,V value){
RBNode node = new RBNode<>();
node.setColor(RED);
node.setKey(key);
node.setValue(value);
insert(node);
}
/**
* 插入元素 先找到parent
* @param node
*/
private void insert(RBNode node){
RBNode parent= null;
RBNode root = this.root;
while(root !=null){
parent = root;
int tem = node.getKey().compareTo(root.getKey());
if(tem > 0){
root = root.right;
}else if(tem == 0){
root.setValue(node.getValue());
return;
}else{
root = root.left;
}
}
if(parent ==null){
this.root = node;
}else{
node.setParent(parent);
int tem = node.getKey().compareTo(parent.getKey());
if(tem > 0){
parent.right = node;
}else{
parent.left = node;
}
}
ficUp(node);
}
/**
* 调整符合红黑树特性的操作
* 情况分为:
* 1.root节点为空 ,插入后将root节点班委黑色。
* 2. 插入节点的父级节点为黑色 不违反红黑树特性 不做调整
* 3. 插入节点已存在 insert中已覆盖
* 4. 插入节点的父级节点为红色:{
* 1. 如果叔叔级节点为红色 为双红 将父级节点和叔叔级节点变为黑色,将爷爷级节点变为红色 以爷爷节点进行再次处理
* 2. 如果叔叔级节点不存在或为黑色:{
* 1. 父级节点在爷爷级节点的left,插入节点在父级节点的left 为(LL)双红 父级变为黑色,爷爷变为红色。 以爷爷节点进行右旋
* 2. 插入节点在父级的右侧,为(LR) 双红, 以父级节点进行左旋 变为(LL双红)
* 3. 父级节点在爷爷级节点的右侧,插入节点在父级节点的right 为(RR)双红 父级变为黑色,爷爷变为红色。 以爷爷节点进行左旋
* 4. 插入节点在父级的左侧 为(RL)双红 , 以父级节点进行右旋 变为(RR)双红
* }
* }
*/
private void ficUp(RBNode node){
this.root.setColor(BLACK);
RBNode parent = getParent(node);
RBNode gParent = getParent(parent);
if(parent !=null && isRed(parent)){
RBNode uncle = null;
if(gParent.left == parent){
uncle = gParent.right;
}else{
uncle = gParent.left;
}
if(uncle != null && isRed(uncle)){
parent.setColor(BLACK);
uncle.setColor(BLACK);
gParent.setColor(RED);
ficUp(gParent);
return;
}else{
if(parent == gParent.left){
if(parent.left == node){
parent.setColor(BLACK);
gParent.setColor(RED);
rightRotate(gParent);
}else{
leftRotate(parent);
ficUp(parent);
return;
}
}else{
if(parent.left == node){
rightRotate(parent);
ficUp(parent);
return;
}else{
parent.setColor(BLACK);
gParent.setColor(RED);
leftRotate(gParent);
}
}
}
}
}
/**
* 中序遍历
*/
public void print(){
RBNode node = this.root;
print(root);
System.out.println("root: "+node.getKey());
}
private void print(RBNode root){
if(root ==null){
return ;
}
print(root.left);
String color=root.getColor()?"红色":"黑色";
System.out.println("key: "+ root.getKey()+" value: "+ root.getValue()+" color: "+ color);
print(root.right);
}
}
编写Test 类进行测试:
public class RBTest {
public static void main(String[] args) {
// int a[] = { 16, 88, 7, 11, 9, 26, 18, 14, 15 };
int a[] = { 1,5,9,2,8,4,6,3,7,15};
RBTree tree = new RBTree();
for(int i = 0;i<a.length;i++){
tree.insert(a[i],null);
}
tree.print();
}
}
OK !