红黑树插入操作分析及代码实现

12 篇文章 1 订阅

首先说一下红黑树的五个性质:

1、每个结点要么是红色的,要么是黑色的;
2、根结点是黑色的;
3、每个叶结点,即空结点(NIL)是黑色的;
4、如果一个结点是红色的,那么它的两个子结点都是黑色的;
5、对每个结点,从该结点到其子结点的所有路径上包含相同数目的黑结点。


在对红黑树插入的时候,我们一般都会插入红色的结点,红黑树的插入主要有这几种情况:

1、插入的是根结点;

     此时,只会违反性质2,那么直接把此结点涂为黑色即可。

2、插入的结点的父节点是黑色的;

     此时什么都不需要做。

3、插入的结点的父节点是红色且叔父结点是红色;

     此时又分为几种情况:
          1)、父节点是祖父结点的左子树还是右子树;     
          2)、插入的结点是父节点的左子树还是右子树。
     无论哪种情况,解决策略都是:
          对插入的结点(当前结点)的父节点和叔父结点涂黑,祖父结点涂红,把当前结点指向祖父结点,递归执行第1种情况。

4、插入的结点的父节点是红色,叔父结点是黑色的。

     这种情况又分为以下几种情况:
     1)、插入结点为父结点的左结点,父节点为祖父结点的左结点;
          解决方案:父节点变黑,祖父结点变红,然后以祖父结点为支点右旋。
     2)、插入结点为父节点的右节点,父节点为祖父结点的左结点;
          解决方案:以当前结点的父节点为支点左旋,然后再以当前结点的左结点执行第1)种情况。
     3)、插入结点为父节点的左结点,父节点为祖父结点的右节点;
          解决方案:以当前结点的父节点为支点右旋,然后再以当前结点的右节点执行第4)中情况。
     4)、插入结点为父节点的右节点,父节点为祖父结点的右节点。
          解决方案:父节点变黑,祖父结点变红,然后以祖父结点为支点左旋。

代码实现如下:

package com.tyxh.rab;

public class TreeNode {
     public int data;
     public TreeNode lchild;
     public TreeNode rchild;
     public TreeNode parent;
     public boolean color;
     public TreeNode( int data, TreeNode lchild, TreeNode rchild,
              TreeNode parent, boolean color) {
           this. data = data;
           this. lchild = lchild;
           this. rchild = rchild;
           this. parent = parent;
           this. color = color;
     }
     
}

package com.tyxh.rab;

public class BTTree {
     public static final boolean RED = false;
     public static final boolean BLACK = true;
     private TreeNode root;

     public BTTree() {
           root = null;
     }

     public TreeNode grandParentNode(TreeNode node) {
           // 获得祖父节点
           return node. parent. parent;
     }

     public TreeNode uncleParentNode(TreeNode node) {
           // 获得叔父节点
           if (node. parent == grandParentNode(node). lchild)
               return grandParentNode(node). rchild;
           else
               return grandParentNode(node). lchild;
     }

     // 左旋
     private void singRotateLeft(TreeNode k2) {
          TreeNode k1 = k2. rchild;
          k2. rchild = k1. lchild;
          k1. lchild = k2;
     }

     // 右旋
     private void singRotateRight(TreeNode k2) {
          TreeNode k1 = k2. lchild;
          k2. lchild = k1. rchild;
          k1. rchild = k2;
     }

     // 插入
     // 1、新结点位于树的根上,没有父节点
     public void insert_case1(TreeNode node) {
           if (node. parent == null)
              node. color = BLACK;
           else
              insert_case2(node);
     }

     // 2、新节点的父节点是黑色的
     public void insert_case2(TreeNode node) {
           if (node. parent. color == BLACK)
               return;
           else
              insert_case3(node);
     }

     // 3、父节点是红色的,叔父节点也是红色的
     public void insert_case3(TreeNode node) {
           if (uncleParentNode(node) != null && uncleParentNode(node).color == RED ) {
              node. parent. color = BLACK;
              uncleParentNode(node). color = BLACK;
              grandParentNode(node). color = RED;
              insert_case1(grandParentNode(node));
          } else
              insert_case4(node);
     }

     // 4、父节点是红色的,叔父结点是黑色的或者为Nil,并且插入结点是父节点的右节点,父节点是祖父结点的左结点
     public void insert_case4(TreeNode node) {
           if (node == node. parent. rchild
                   && node. parent == grandParentNode(node).lchild) {
               // 以node.parent为结点左旋
              singRotateLeft(node. parent);
              node = node. lchild;
          } else if (node == node. parent. lchild
                   && node. parent == grandParentNode(node).rchild) {
               // 以node.parent为结点右旋
              singRotateRight(node. parent);
              node = node. rchild;
          }
          insert_case5(node);
     }

     // 5、父亲结点是红色的,叔父是黑色的或者为Nil,并且插入结点是父节点的左结点,父节点是祖父结点的左结点
     public void insert_case5(TreeNode node) {
          node. parent. color = BLACK;
          grandParentNode(node). color = RED;
           if (node == node. parent. lchild
                   && node. parent == grandParentNode(node).lchild) {
               // 以祖父结点为结点右旋
              singRotateRight(grandParentNode(node));
          } else if (node == node. parent. rchild
                   && node. parent == grandParentNode(node).rchild) {
               // 以祖父结点为结点左旋
              singRotateLeft(grandParentNode(node));
          }

     }

     // 中序遍历
     public void traversal() {
          insubtree( root);
     }

     private void insubtree(TreeNode node) {
           if (node == null)
               return;
          insubtree(node. lchild);
          System. out.println(node. data + "、");
          insubtree(node. rchild);
     }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值