04树 + 堆 + 优先队列 + 图(D1_树(D5_红黑树(RBT)))

目录

一、基本介绍

二、红黑树的Java实现

1. 基本定义

2. 常用方法

左旋

右旋

添加

添加修正

删除

删除修正

3. 完整源码


一、基本介绍

R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。

红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

红黑树的特性(规则):

(1)每个节点或者是黑色(Black),或者是红色(Red)。

(2)根节点是黑色(Black)。

(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]

(4)如果一个节点是红色的,则它的子节点必须是黑色的。

(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

注意

(01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。

(02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。

因此,满足以上五条特性的二叉树就叫做红黑树

二、红黑树的Java实现

1. 基本定义

红黑树的基本操作是添加删除旋转。在对红黑树进行添加或删除后,会用到旋转方法。

为什么呢?道理很简单,添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树

的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。

而通过旋转,可以使这颗树重新成为红黑树。

简单点说,旋转的目的是让树保持红黑树的特性。

旋转包括两种:左旋右旋

下面分别对红黑树的基本操作进行介绍。

红黑树的基本类的实现代码


/* 用内部类的方式实现Node类  */
public class RBTree<T> implements Tree<T> {

    private RBTNode<T> root;//根节点
    private static final boolean BLACK = true;
    private static final boolean RED = false; 
    
    private class RBTNode<T>{
        
        T key;              // 关键字(键值)
        
        boolean color;      //颜色 
        RBTNode<T> parent; //父亲节点
        
        RBTNode<T> lchild;//左孩子
        RBTNode<T> rchild;//右孩子
        
        public RBTNode() {
            // TODO Auto-generated constructor stub
        }
        
        public RBTNode(T key,boolean color,RBTNode<T> parent,RBTNode<T> lchild,RBTNode<T> rchild) {
            this.key = key;
            this.color = color;
            this.parent = parent;
            this.lchild = lchild;
            this.rchild = rchild;
        }
        
        
    }

    ......
}	

注意:RBTree是红黑树对应的类,RBTNode是红黑树的节点类,Tree是红黑树对应的API接口,在

RBTree中包含了根节点mRoot和红黑树的相关API。

2. 常用方法

左旋

左旋的实现代码

    //左旋
    private void leftRotate(RBTNode<T> x) {
        //当前是针对x节点进行左旋
        
        //设y为x的右孩子,经过左旋y就会到x当前的位置
        RBTNode<T> y = x.rchild;
        //将y的左孩子设为x的右孩子
        x.rchild = y.lchild;
        
        //如果y的左孩子非空的话就设置它的父节点,
        //不然就是空节点,空节点无必要设置父节点
        if(y.lchild != null) {
            //将x设为y的左孩子的父节点
            y.lchild.parent = x;
        }
        
        //将x的父节点设为y的父节点
        y.parent = x.parent;
        
        if(x.parent != null) {            //如果x的父节点非空
            if(x.parent.lchild == x) {    
                x.parent.lchild = y;      //如果x为它父节点的左孩子,则将y设为x父节点的左孩子
            }else {
                x.parent.rchild = y;      //如果x为它父节点的右孩子,则将y设为x父节点的右孩子
            }
        }else {
            this.root = y;               //如果x父节点为空,则将y设为根节点
        }
        
        y.lchild = x;  //将x设为y的左孩子        
        x.parent = y;  //最后再将y设为x的父节点,左旋到此结束!
        
    }

右旋

右旋的实现代码

    
    //右旋
    private void rightRotate(RBTNode<T> x) {
        //当前是针对x节点进行右旋
        
        //设y为x的左孩子,经过右旋y就会到x当前的位置
        RBTNode<T> y = x.lchild;
        //将y的右孩子设为x的左孩子
        x.lchild = y.rchild;
        
        //如果y的右孩子非空的话就设置它的父节点,
        //不然就是空节点,空节点无必要设置父节点
        if(y.rchild != null) {
            //将x设为y的右孩子的父节点
            y.rchild.parent = x;
        }
        
        //将x的父节点设为y的父节点
        y.parent = x.parent;
        
        if(x.parent != null) {             //如果x的父节点非空
            if(x.parent.lchild == x) {
                x.parent.lchild = y;       //如果x为它父节点的左孩子,则将y设为x父节点的左孩子
            }else {
                x.parent.rchild = y;       //如果x为它父节点的右孩子,则将y设为x父节点的右孩子
            }
        }else {
            this.root = y;                 //如果x父节点为空,则将y设为根节点 
        } 
        
        y.rchild = x;   //将x设为y的左孩子        
        x.parent = y;   //最后再将y设为x的父节点,左旋到此结束!
        
    }

添加


    //插入节点
	private void insert(RBTNode<T> node) {
		RBTNode<T> mroot = this.root;
		RBTNode<T> nodeparent = null;
		
		//以二叉查找树的方式插入节点就行
		while(mroot!=null) {
			nodeparent = mroot;
			if((int)node.key<(int)mroot.key) {
				mroot = mroot.lchild;
			}else {
				mroot = mroot.rchild;
			}
		}
		
		//设置插入节点的父亲节点
		node.parent = nodeparent;
		
		if(nodeparent != null) {
			if((int)node.key<(int)nodeparent.key) {
				nodeparent.lchild = node;
			}else {
				nodeparent.rchild = node;
			}
		}else {
			this.root = node;
		}
		
		
		//每次插入节点后进行设置颜色默认为红色,然后进插入修正使之成为红黑树
		setRed(node);
		
		//进入插入修正算法,是红黑树中的核心算法之一
		insertFixUp(node);
		
	}
	
	//公开的插入方法
	public void insert(T key) {
		RBTNode<T> node = new RBTNode<T>(key, this.BLACK, null, null, null);
		//如果新建节点非null进入插入节点方法,不然返回
		if(node != null) {
			insert(node);
		}
		
	}

添加修正


    //插入修正算法,红黑树的核心算法之一
    private void insertFixUp(RBTNode<T> node) {
        //插入节点node的父亲节点,祖父节点和叔叔节点
        RBTNode<T> parent,gparent,uncle;
        
        //父亲节点非空 并且 父亲节点为红色才会进入
         while(((parent=parentOf(node)) != null) && isRed(parent)) {
            
            gparent = parentOf(parent);
            
            
            if(gparent.lchild == parent) {
                
                uncle = gparent.rchild;
                
                //Case 1条件: 叔叔节点是红色节点
                if(uncle!=null && isRed(uncle)) {
                    
                    //操作
                    setBlack(parent);
                    setBlack(uncle);
                    setRed(gparent);
                    
                    node = gparent;
                    
                    continue;
                }else {
                    
                    //Case 2条件: 叔叔节点是黑色节点,且当前节点是父亲节点的右孩子
                    if(parent.rchild == node) {
                        
                        //操作
                        leftRotate(parent);
                        RBTNode<T> tmp = parent;
                        parent = node;
                        node = tmp;
                        
                    }
                    
                    //Case 3条件: 叔叔节点是黑色节点,且当前节点是父亲节点的左孩子
                    
                    //操作
                    setBlack(parent);
                    setRed(gparent);
                    rightRotate(gparent);
                    
                }
                
                
            }else {  //同理(左右相反)
                
                uncle = gparent.lchild;
                
                //Case 1条件: 叔叔节点是红色
                if(uncle!=null && isRed(uncle)) {
                    
                    //操作
                    setBlack(parent);
                    setBlack(uncle);
                    setRed(gparent);
                    
                    node = gparent;
                    
                    continue;
                }else {
                    
                    //Case 2条件: 叔叔节点是黑色,且当前节点是父亲节点的左孩子
                    if(parent.lchild == node) {
                        
                        //操作
                        rightRotate(parent);
                        RBTNode<T> tmp = parent;
                        parent = node;
                        node = tmp;
                        
                    }
                    
                    //Case 3条件: 叔叔节点是黑色,且当前节点是父亲节点的右孩子
                    
                    //操作
                    setBlack(pare
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodingW丨编程之路

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值