将二分查找法用数据结构来表示===》二叉搜索树
二叉树的节点删除情况:
1、删除叶子结点,直接删除即可
2、删除非叶子结点,但是该节点只有一个孩子结点的话,直接用孩子结点补上即可
3、删除有两个孩子的结点,找到该节点的前驱结点/后继结点,交换位置以后删除该节点即可!!
![图片说明](https://uploadfiles.nowcoder.com/images/20200612/239411106_1591973531617_C739363AC1728CB6261EA85F530076C0 "图片标题")
其定义是:
![图片说明](https://uploadfiles.nowcoder.com/images/20200606/239411106_1591424409206_6AFCD4C401DEF2B089F098CC6AD64AB5 "图片标题")
但是二叉搜索树如果遇到以下这种情况的时候效率很低,时间复杂度很高,以下是查找8的元素:
![图片说明](https://uploadfiles.nowcoder.com/images/20200606/239411106_1591424423730_650739FD35D762D7139A1A5F4F8EE89F "图片标题")
不符合我们使用二叉搜索树的初衷(类似于二分法,更高效的查找数据)===》引出了自平衡二叉搜索树,避免退化成链表查找((AVL)/红黑树)

AVL(平衡二叉搜索树):空树/每个节点的左子树深度与右子树深度之差的绝对值不超过1
红黑树在平衡性上没那么高要求,具体看红黑树的性质!
![图片说明](https://uploadfiles.nowcoder.com/images/20200606/239411106_1591424436228_36FB2BD1B0ED9BCF44C3161EA89E93A3 "图片标题")


红黑树

  1. 定义:是一种特殊的二叉搜索树,本质上是二叉搜索树,不过是特殊的,用于高效的查找数据的一种算法
  2. 性质:
  • 根节点一定是黑色的
  • 每个节点不是红色就是黑色
  • 不可能有连在一起的红色节点,也就相当于每个红色节点的子节点都是黑色的,所有的叶子结点都是黑色的,这里的叶子结点不是说没有子树的结点,而是对于每个为空NULL的结点,在红黑树中称为叶子结点,如下图所示,NULL对应的结点是黑色的
  • 从一个结点到该节点的子孙结点的所有路径上包含相同数目的黑结点!!==》红黑树是接***衡的二叉树
    ![图片说明](https://uploadfiles.nowcoder.com/images/20200606/239411106_1591424453848_1202BCBFF33F3F9720F871F9855C4561 "图片标题")
    根据这个性质,构造出来的二叉搜索树是相对平衡的

3.为了满足以上的性质,需要对二叉搜索树进行以下几种操作(当然也可能是不做任何操作,根据二叉树插入节点的性质插入节点以后仍然满足红黑树的性质)

可以对照着四张图的那张图和以下的图去分析(更容易懂):
![图片说明](https://uploadfiles.nowcoder.com/images/20200606/239411106_1591424574963_C7D241F1EFBA3D93BA1434CADF4AE37D "图片标题")

注意:红黑树插入节点有两个步骤:
1、根据二叉搜索树插入节点
2、根据红黑树的性质调整树的结构以满足红黑树的性质
红黑树的部分源码:

  • 红黑树中的结点定义
    class RBTNode//定义每个节点所包含的内容
    {
    public:
      RBTcolor color;    // 颜色
      T key;            // 关键字(键值)
      RBTNode *left;    // 左孩子
      RBTNode *right;    // 右孩子
      RBTNode *parent; // 父结点
      RBTNode(T val,RBTNode *l,RBTNode *r,RBTNode *p,RBTcolor col):key(val),left(l),right(r),parent(p),color(col){}
    };
  • 左旋:
    void leftromate(RBTNode *x)//给定一个指针,指向左旋以该节点开始旋转的一个结点
    {
      RBTNode *y=x->right;
      if(x->parent)
      {
          x->parent->left=y;
          y->parent=x->parent;
      }
      else
          y->parent=x->parent;
      x->parent=y;
      x->right=y->left;
      if(y->left)
          y->left->parent=x;
      y->left=x;
    }
  • 右旋:
void rightromate(RBTNode *x)//给定一个指针,指向右旋以该节点开始旋转的一个结点
{
    RBTNode *y=x->left;
    if(x->parent)
    {
        x->parent->left=y;
        y->parent=x->parent;
    }
    else
        y->parent=x->parent;
    x->left=y->right;
    if(y->right)
        y->right->parent=x;
    y->right=x;
    x->parent=y;
}

红黑树的删除步骤如下:(结点的度:即该节点所含子树的个数)
1、直接删除
查看需要删除的结点所处的位置,如果该节点是度为0的结点,直接删除即可,删除完以后的树仍然为红黑树
2、取代删除
查看需要删除的结点所处的位置,如果该节点是度为1的结点,直接用孩子结点取代即可,取代之后如果出现不符合红黑树的性质的话,按照上面插入结点的规则进行调整操作,直到满足红黑树性质为止
3、前驱/后继结点取代删除
查看需要删除的结点所处的位置,如果该节点是度为2的结点,将该节点的前驱结点或者后继结点与该节点进行交换,然后观察是否符合1/2的条件,如果不符合继续使用其结点的前驱/后继结点进行交换,直到满足1/2的条件,然后删除,当然,如果出现删除后不满足红黑树的性质的情况的话,按照上面插入结点的规则进行调整操作,直到满足红黑树性质为止

图片说明