数据结构笔记8: 搜索树

二叉搜索树(BST)

BST定义

  • 所有的关键字只能出现一遍
  • 左子树所有节点的关键值小于根节点,右子树所有节点的关键值大于根节点
  • 左右子树也都是二叉搜索树 ➡️递归

索引二叉搜索树

  • 每个节点记录一个索引值(左子树大小+1)➡️节点在以它为根的子树中的排名
  • 如何找到第k元?
  • 如何确定一个节点的关键值是整棵树的第几大?
template<class E, class K>
class BSTree : public BinaryTree<E> { //由二叉树派生
public:
    bool Search(const K& k, E& e) const; 
    BSTree<E,K>& Insert(const E& e); 
    BSTree<E,K>& Delete(const K& k, E& e); 
    void Ascend() {InOutput();} //升序输出:中序遍历
};

BST搜索

算法

  • 从根节点开始将key与节点值比较
  • 如果key小于节点值,进入左子树,如果大于节点值,进入右子树
  • 递归,直到找到或子树为空停止

平均查找长度

  • 成功:(需要比较找到节点的次数*同一层有几个节点)的累加和除总节点数
  • 失败:(需要比较确认搜索失败的次数*同一层有几个空子树)的累加和除总空子树

搜索函数: O(log n)~O(n)

template<class E, class K>
bool BSTree<E,K>::Search(const K& k, E &e) const {
    BinaryTreeNode<E> *p = root; 
    while (p)
        if (k < p->data) 
            p = p->LeftChild;
        else if (k > p->data) 
            p = p->RightChild;
            else {
                e = p->data;
                return true;
            }
    return false;
}

BST插入

算法

  • 先进行搜索操作
  • 若成功,表明有重复关键字,插入失败
  • 若失败,搜索结束的位置即为插入位置
  • 新插入的节点一定是一个叶子节点

插入函数: O(log n)~O(n)

template<class E, class K>
BSTree<E,K>& BSTree<E,K>::Insert(const E& e) {
    BinaryTreeNode<E> *p = root, //搜索指针
                        *pp = 0; //搜索指针的父指针
    while (p) { //找到应该插入的位置
        pp = p;
        if (e < p->data) 
            p = p->LeftChild;
        else if (e > p->data) 
            p = p->RightChild;
        else //关键值重复
            throw BadInput(); 
    }
    BinaryTreeNode<E> *r = new BinaryTreeNode<E> (e);
    if (root) { //如果树不为空
        if (e < pp->data) 
            pp->LeftChild = r;
        else 
            pp->RightChild = r;
    }
    else //如果树为空 
        root = r;
    return *this;
}

BST删除

算法

  • 删除叶节点:直接丢弃,即将父节点指向它的指针置零
  • 删除有且仅有一个非空子树的节点:丢弃节点,其子树取代它原来的位置
  • 删除有两个非空子树的节点:节点的左子树中最大的元素或右子树中最小的元素替代它

删除函数: O(log n)~O(n)

template<class E, class K>
BSTree<E,K>& BSTree<E,K>::Delete(const K& k, E& e){
    BinaryTreeNode<E> *p = root, //搜索指针
                        *pp = 0; //搜索指针的父指针
    while (p && p->data != k) {
        pp = p;
        if (k < p->data) 
            p = p->LeftChild; 
        else 
            p = p->RightChild;
    }
    if (!p) //如果不存在
        throw BadInput();
    e = p->data;
    if (p->LeftChild && p->RightChild) { //如果两个子树均不为空
        BinaryTreeNode<E> *s = p->LeftChild,
                            *ps=p;
        while (s->RightChild) { //找到左子树里的最大节点(最右)
            ps = s;
            s = s->RightChild;
        }
        p->data = s->data; //交换两个节点
        p = s;
        pp = ps;
    }
    //最多只有一个子树
    BinaryTreeNode<E> *c;
    if (p->LeftChild) 
        c = p->LeftChild; 
    else 
        c = p->RightChild;
    if (p == root) 
        root = c;
    else {
        if (p == pp->LeftChild) 
            pp->LeftChild = c;
        else 
            pp->RightChild = c;
    } 
    delete p;
    return *this;
}

缺陷

  • 仅对树节点的大小关系做出约束,而没有对树高做出约束
  • 树越高,搜索、插入、删除的性能越差

平衡二叉搜索树(AVL)

AVL定义

  • AVL是特殊的BST
  • 左子树和右子树是AVL树 ➡️递归
  • 左子树和右子树的树高差不超过1 ➡️对树高做出约束
  • 空二叉树是AVL树

AVL树的描述

  • 平衡因子bf=左子树高度-右子树高度

AVL搜索(同BST)

AVL插入

算法

  • 利用BST的插入算法,先把数据插入
  • 如果出现不平衡的情况,即平衡因子bf=\pm 2,则调整结构
  • 追踪从根节点到插入位置路径上的节点,原来平衡因子bf=\pm 1的节点有可能不平衡
  • 如果出现不平衡,新节点一定是插入了本来较高的子树,找到离新节点最近的不平衡节点,如果插入左子树的左子树,则称为LL型
  • LL型不平衡及其调整方法

  • LR型不平衡及其调整方法

AVL删除

算法

  • 利用BST的删除操作,先把数据删除
  • 如果出现不平衡的情况,即平衡因子bf=\pm 2,则调整结构
  • 如果出现不平衡,一定是在本来较矮的子树上删除了一个节点,找到离删除节点最近的不平衡节点,如果删除了其右子树,其左子树的平衡因子为0,则成为R0型
  • R0型不平衡的调整,处理完后局部高度未变,祖先平衡因子不需要调整

  • R1型不平衡的调整,处理完后局部高度-1,需要往上继续修正

  • R-1型不平衡的调整,处理完后局部高度-1,需要往上继续修正

B树

动机:建立索引

m叉搜索树

定义

  • 在相应的扩充搜索树中(用外部节点替换零指针),每个内部节点最多可以有m个子女及m-1个元素(外部节点不含元素和子女)
  • 每个含p个元素的节点,有p+1个子女
  • 每个节点内部元素升序排列,子女的大小界在父节点相应的元素之间

搜索

  • 从根节点开始向下搜索
  • 对每个节点,如果能找到关键字,搜索成功,如果关键字的大小在节点内的两个元素之间,在子树中继续寻找
  • 如果到达外部节点,则搜索失败

插入

  • 先进行搜索操作,如果成功则插入失败(关键值不能重复)
  • 如果失败,在失败的位置进行插入,如果能够在同级插入就插入,保持树尽量扁平

删除

  • 先进行搜索操作,如果失败则删除失败
  • 左右子树均为空,直接进行删除
  • 左右子树不都为空,子树中元素提升,替代被删除的元素

高度

  • 高度为h,最少h​​​​​​​个元素,最多m^{h}-1
  • n个元素,高度n{log_{m}}^{n+1}

m阶的B树

定义

  • 是m叉搜索树
  • 根节点至少有2个孩子
  • 除根节点外,所有内部节点至少有\left \lceil \frac{m}{2} \right \rceil个孩子(取上界)
  • 所有外部节点位于同一层上 ➡️方便数据库的索引

高度

  • 设T是一棵高度为h的m阶B树,d= \left \lceil \frac{m}{2} \right \rceil且n是T中的元素个数,则 
  • 2d^{h-1}-1\leqslant n\leqslant m^{h}-1
  • {log_{m}}^{n+1}\leqslant h\leqslant {log_{d}}^{(n+1)/2}+1

插入操作

  • 先进行搜索操作,如果可以在同一层插入,则插入
  • 如果同一层满了,先插入,再把这棵子树分裂成两棵,把最中间的元素提上去

删除操作

  • 删除叶节点中元素,能借就借,不能借就合并
    • 如果不符合最小元素的数目,和兄弟节点借一个
    • 如果大小关系不符合,向父节点借一个
    • 如果借不了,就合并
  • 删除非叶节点元素,类似AVL树,子树叶节点元素与之交换

B+树

定义

  • 所有有效的关键字都放在叶节点中,上层的非叶节点的关键字是其子树中最大关键字的拷贝
  • 叶节点包含了全部关键字,且叶节点本身按关键字值从小到大链接
  • 一个叶节点可以有m个元素

插入操作

  • 通过查找,在叶节点的适当位置插入
  • 如果插入后不符合定义,将该叶节点均匀分裂,更新其父节点
  • 递归检查其父节点在更新后是否满足定义

删除操作

  • 删除叶节点
  • 如果不满足最小元素的要求,从兄弟节点借一个
  • 如果借不了,合并兄弟节点
  • 递归检查父节点是否满足定义

红黑树

定义

  • 特殊的二叉扩充搜索树
  • 根节点和所有外部节点的颜色是黑的
  • 根节点到外部节点的路径上没有连续红节点
  • 所有根到外部节点的路径具有相同数目的黑节点
  • 节点的:从该节点到其子树中任一外部节点的路径上的黑色指针数目

2-3-4树的红黑树表示

红黑树特性

  • 若P、Q是红黑树中两条从根至外部节点的路径,那么length(P)\leqslant 2length(Q)
  • 设h是一棵红黑树的高度( 不包括外部节点),n是树中内部节点的数目,而r是根节点的阶
    • h\leqslant 2r
    • n\geqslant 2^{r}-1
    • h\leqslant 2{log_{2}}^{n+1}

插入操作

  • 先进行二叉搜索树的插入方法
  • 新节点应该是红色
  • 如果出现连续红边,要调整树的结构,参考2-3-4树的插入操作​​​​​​​。看祖父的另一个孩子是什么颜色:
    • XYb(如果2-3-4树中节点没有挤爆):旋转变色,根黑子红
    • XYr(如果2-3-4树中节点被挤爆了):不转变色,根红子黑

删除操作

  • 删除非叶节点的,与中序遍历的后继节点交换
  • 删除叶节点,如果是红节点,结束
  • 如果是黑节点,调整结构

作业8

  • 计算AVL树的高度
  • 返回离AVL树根节点最近的值
// 13 5 2 8 7 9 23 77 0 12

template<typename T>
class AVLtree;

template<typename T>
class treeNode {
    friend AVLtree<T>;  //声明友元
public:
    treeNode(){
        parent=leftchild=rightchild=NULL;
        h=0;
    }
    treeNode(const T& t){
        data=t;
        parent=leftchild=rightchild=NULL;
        h=1;
    }
private:
    T data;
    int h; //记录节点的高度
    treeNode<T> *parent;
    treeNode<T> *leftchild;
    treeNode<T> *rightchild;
};

template<typename T>
class AVLtree {
public:
    AVLtree(){
        root=NULL;
    }
    int height(){ //树的高度即根节点的高度
        if(root)
            return root->h;
        else
            return 0;
    }
    treeNode<T>* find(T& t){ //找到应该插入的位置的父节点
        treeNode<T> *p=root,*pp=NULL; //p为应该插入的位置,pp为p的父节点
        while(p){
            pp=p;
            if(t<p->data) //如果关键值比当前节点的关键值小,进入左子树
                p=p->leftchild;
            else if(t>p->data) //如果关键值比当前节点的关键值大,进入右子树
                p=p->rightchild;
            else{ //如果关键值等于当前节点的关键值
                pp=NULL;
                break;
            }
        }
        return pp;
    }
    AVLtree<T>& insert(T &t){ //插入关键值
        treeNode<T> *p=find(t); //找到应该插入的位置的父节点
        treeNode<T> *q=new treeNode<T>; //新建节点
        q->data=t;
        q->h=1;
        q->parent=p;
        if(!p){ //如果父节点为空
            if(root){ //树不为空,说明关键值重复
                cout<<"Data exists!"<<endl;
            }
            else{ //树为空
                root=q;
            }
            return *this;
        }
        if(t<p->data) //如果关键值小于父节点的值
            p->leftchild=q;
        else //如果关键值大于父节点的值
            p->rightchild=q;
        if(p->rightchild==NULL||p->leftchild==NULL){ //如果父节点原来没有孩子,高度变化
            p->h++;
            while(p->parent&&(p->parent->h-p->h)!=1){ //往上寻找,更新高度
                p=p->parent;
                p->h++;
            }
        }
        while(q->parent){ //从新节点往上寻找,是否有违反AVL树定义的节点
            q=q->parent;
            int lh,rh;
            if(q->leftchild)
                lh=q->leftchild->h;
            else
                lh=0;
            if(q->rightchild)
                rh=q->rightchild->h;
            else
                rh=0;
            if((lh-rh)==2||(rh-lh)==2){ //如果失衡
                treeNode<T> *s=q->parent;
                int type;
                if(!s)
                    type=0;
                else if(s->leftchild==q)
                    type=1;
                else
                    type=2;
                if((lh-rh)==2){ //左子树失衡
                    if(q->leftchild->leftchild)
                        lh=q->leftchild->leftchild->h;
                    else
                        lh=0;
                    if(q->leftchild->rightchild)
                        rh=q->leftchild->rightchild->h;
                    else
                        rh=0;
                    if(lh>rh) //LL型
                        q=LLrotation(q);
                    else //LR型
                        q=LRrotation(q);
                }
                else if((rh-lh)==2){ //右子树失衡
                    if(q->rightchild->leftchild)
                        lh=q->rightchild->leftchild->h;
                    else
                        lh=0;
                    if(q->rightchild->rightchild)
                        rh=q->rightchild->rightchild->h;
                    else
                        rh=0;
                    if(lh>rh) //RL型
                        q=RLrotation(q);
                    else //RR型
                        q=RRrotation(q);
                }
                //以上只改变了q指向的位置,要把q在树中的位置也更新!!
                if(type==0)
                    root=q;
                else if(type==1)
                    s->leftchild=q;
                else if(type==2)
                    s->rightchild=q;
                //调整结构之后,往上寻找,更新节点的高度
                while(s){
                    if(s->leftchild)
                        lh=s->leftchild->h;
                    else
                        lh=0;
                    if(s->rightchild)
                        rh=s->rightchild->h;
                    else
                        rh=0;
                    s->h=(lh>rh)? lh+1:rh+1;
                    s=s->parent;
                }
            }
        }
        return *this;
    }
    treeNode<T>* LLrotation(treeNode<T>* q){ //LL型
    /*
            q            p
         p    z  ➡️   x    q
       x  y          t    y  z
     t
    */
        treeNode<T> *p=q->leftchild;
        q->leftchild=p->rightchild;
        p->parent=q->parent;
        p->rightchild=q;
        q->parent=p;
        if(q->leftchild)
            q->leftchild->parent=q;
        int lh,rh;
        if(q->leftchild)
            lh=q->leftchild->h;
        else
            lh=0;
        if(q->rightchild)
            rh=q->rightchild->h;
        else
            rh=0;
        q->h=(lh>rh)? lh+1:rh+1;
        if(p->leftchild)
            lh=p->leftchild->h;
        else
            lh=0;
        if(p->rightchild)
            rh=p->rightchild->h;
        else
            rh=0;
        p->h=(lh>rh)? lh+1:rh+1;
        return p;
    }
    treeNode<T>* LRrotation(treeNode<T>* q){ //LR型,相当于先RR,再LL
    /*
            q             q             y
         z     w  ➡️   y    w   ➡️   z    q
       x  y           z  t          x    t  w
            t        x
    */
        q->leftchild=RRrotation(q->leftchild);
        return LLrotation(q);
    }
    treeNode<T>* RLrotation(treeNode<T>* q){ //RL型,相当于先LL,再RR
     /*
            q             q                 x
         w      z  ➡️   w    x      ➡️   q    z
              x  y          t  z        w  t    y
            t                    y
    */
        q->rightchild=LLrotation(q->rightchild);
        return RRrotation(q);
    }
    treeNode<T>* RRrotation(treeNode<T>* q){ //RR型
    /*
            q                 p
         z    p       ➡️   q    y
            x   y         z  x    t
                  t
    */
        treeNode<T> *p=q->rightchild;
        q->rightchild=p->leftchild;
        p->parent=q->parent;
        p->leftchild=q;
        q->parent=p;
        int lh,rh;
        if(q->leftchild)
            lh=q->leftchild->h;
        else
            lh=0;
        if(q->rightchild)
            rh=q->rightchild->h;
        else
            rh=0;
        q->h=(lh>rh)? lh+1:rh+1;
        if(p->leftchild)
            lh=p->leftchild->h;
        else
            lh=0;
        if(p->rightchild)
            rh=p->rightchild->h;
        else
            rh=0;
        p->h=(lh>rh)? lh+1:rh+1;
        return p;
    }
    treeNode<T>* getRoot(){ //返回根节点
        return root;
    }
    treeNode<T>* findNear(T& t){ //寻找离根节点最近的节点,并赋值给t
        treeNode<T> *lmax=root->leftchild; //左子树中最大的
        treeNode<T> *rmin=root->rightchild; //右子树中最小的
        while(lmax->rightchild)
            lmax=lmax->rightchild;
        while(rmin->leftchild)
            rmin=rmin->leftchild;
        if((root->data-lmax->data)<=(rmin->data-root->data)){
            t=lmax->data;
            return lmax;
        }
        else{
            t=rmin->data;
            return rmin;
        }
    }
private:
    treeNode<T> *root;
};

int main(){
    AVLtree<int> avl;
    int t;
    cout<<"Please input data for AVL tree!"<<endl;
    for(int i=0;i<10;i++){
        cin>>t;
        avl.insert(t);
    }
    cout<<"Height: "<<avl.height()<<endl;
    int near;
    avl.findNear(near);
    cout<<"The nearest tree-node of root is: "<<near<<endl;
}

作业9

红黑树动态示意图:Red/Black Tree Visualization

无重复值的红黑树描述

//50 60 65 80 5 10 62 70 23 13
//5 13 50 65 80

template<typename T>
class treeNode;

template<typename T>
class bsTree {
public:
    virtual treeNode<T>* find(const T& t)=0;
    virtual bsTree<T>& insert(const T& t)=0;
    virtual bsTree<T>& deleted(const T& t)=0;
    virtual void ascend(treeNode<T> *t)=0;
};

template<typename T>
class redBlackTree;

template<typename T>
class treeNode {
    friend redBlackTree<T>;  //声明友元
public:
    treeNode(){
        parent=leftchild=rightchild=NULL;
        color=-1;
    }
    treeNode(const T& t){
        data=t;
        parent=leftchild=rightchild=NULL;
        color=-1;
    }
private:
    T data;
    int color;
    treeNode<T> *parent;
    treeNode<T> *leftchild;
    treeNode<T> *rightchild;
};

template<typename T>
class redBlackTree: public bsTree<T> {
public:
    redBlackTree(){
        root=NULL;
    }
    treeNode<T>* find(const T& t) {
        treeNode<T> *p=root,*pp=NULL; //p为应该插入的位置,pp为p的父节点
        while(p){
            pp=p;
            if(t<p->data) //如果关键值比当前节点的关键值小,进入左子树
                p=p->leftchild;
            else if(t>p->data) //如果关键值比当前节点的关键值大,进入右子树
                p=p->rightchild;
            else{ //如果关键值等于当前节点的关键值
                break;
            }
        }
        return pp;
    }
    bsTree<T>& insert(const T& t) {
        treeNode<T> *p=find(t); //找到应该插入的位置的父节点
        treeNode<T> *q=new treeNode<T>; //新建节点
        q->data=t;
        q->parent=p;
        q->color=1;
        if(!p){ //如果父节点为空,说明树为空
            q->color=-1;
            root=q;
            return *this;
        }
        if(t==p->data){ //关键值存在
            cout<<"Data exists!"<<endl;
            return *this;
        }
        else if(t<p->data) //如果关键值小于父节点的值
            p->leftchild=q;
        else //如果关键值大于父节点的值
            p->rightchild=q;
        treeNode<T>*pp=p->parent;
        treeNode<T>*s=new treeNode<T>;
        while(p){
            pp=p->parent;
            if(q->color==p->color==1){
                if(pp)
                    s=pp->parent;
                else
                    s=NULL;
                int type;
                if(!s)
                    type=0;
                else if(s->leftchild==pp)
                    type=1;
                else
                    type=2;
                if(pp->leftchild==p){
                    if(!pp->rightchild||pp->rightchild->color==-1){
                        if(p->leftchild==q)
                            pp=xybLL(pp);
                        else
                            pp=xybLR(pp);
                    }
                    else
                        pp=xyr(pp);
                }
                else{
                    if(!pp->leftchild||pp->leftchild->color==-1){
                        if(p->leftchild==q)
                            pp=xybRL(pp);
                        else
                            pp=xybRR(pp);
                    }
                    else
                        pp=xyr(pp);
                }
                if(type==0){
                    root=pp;
                    if(root->color==1){
                        root->color=-1;
                        /*
                        if(pp->leftchild==p&&p->leftchild==q)
                            root=xybLL(root);
                        else if(pp->leftchild==p&&p->rightchild==q)
                            root=xybLR(root);
                        else if(pp->rightchild==p&&p->leftchild==q)
                            root=xybRL(root);
                        else
                            root=xybRR(root);
                         */
                    }
                }
                else if(type==1){
                    s->leftchild=pp;
                }
                else{
                    s->rightchild=pp;
                }
                if(pp->color==-1)
                    break;
                else{
                    q=p->parent;
                    if(q)
                        p=q->parent;
                    else
                        p=NULL;
                }
            }
            else
                break;
        }
        return *this;
    }
    treeNode<T>* xybLL(treeNode<T>* pp){
        treeNode<T>*p=pp->leftchild;
        pp->leftchild=p->rightchild;
        if(p->rightchild)
            p->rightchild->parent=pp;
        p->rightchild=pp;
        p->parent=pp->parent;
        pp->parent=p;
        pp->color*=-1;
        p->color*=-1;
        return p;
    }
    treeNode<T>* xybLR(treeNode<T>* pp){
        treeNode<T>*p=pp->leftchild;
        treeNode<T>*q=p->rightchild;
        q->parent=pp->parent;
        pp->leftchild=q->leftchild;
        q->leftchild=p;
        p->rightchild=q->rightchild;
        q->rightchild=pp;
        p->parent=q;
        pp->parent=q;
        pp->color=1;
        q->color=-1;
        return q;
    }
    treeNode<T>* xybRL(treeNode<T>* pp){
        treeNode<T>*p=pp->rightchild;
        treeNode<T>*q=p->leftchild;
        q->parent=pp->parent;
        pp->rightchild=q->rightchild;
        p->leftchild=q->leftchild;
        q->leftchild=pp;
        q->rightchild=p;
        p->parent=q;
        pp->parent=q;
        q->color=-1;
        pp->color=1;
        return q;
    }
    treeNode<T>* xybRR(treeNode<T>* pp){
        treeNode<T>*p=pp->rightchild;
        pp->rightchild=p->leftchild;
        if(p->leftchild)
            p->leftchild->parent=pp;
        p->leftchild=pp;
        p->parent=pp->parent;
        pp->parent=p;
        pp->color*=-1;
        p->color*=-1;
        return p;
    }
    treeNode<T>* xyr(treeNode<T>* pp){
        pp->color=1;
        if(pp->leftchild)
            pp->leftchild->color=-1;
        if(pp->rightchild)
            pp->rightchild->color=-1;
        return pp;
    }
    bsTree<T>& deleted(const T& t){
        treeNode<T> *p=find(t); //找到应该删除的位置
        if(!p||p->data!=t){
            cout<<"Delete failure!"<<endl;
            return *this;
        }
        treeNode<T> *pp=p->parent;
        int type;
        if(!pp)
            type=0;
        else if(pp->leftchild==p)
            type=1;
        else
            type=2;
        if(p->color==1){ //红色
            if(p->rightchild&&p->leftchild){ //有两个孩子
                while(p->leftchild&&p->rightchild){
                    pp=p->parent;
                    if(!pp)
                        type=0;
                    else if(pp->leftchild==p)
                        type=1;
                    else
                        type=2;
                    treeNode<T> *q=p->leftchild;
                    treeNode<T> *c=p->rightchild;
                    p->leftchild=q->leftchild;
                    p->rightchild=q->rightchild;
                    if(q->leftchild)
                        q->leftchild->parent=p;
                    if(q->rightchild)
                        q->rightchild->parent=p;
                    q->rightchild=c;
                    c->parent=q;
                    q->leftchild=p;
                    q->parent=p->parent;
                    p->parent=q;
                    q->color=p->color;
                    p->color=-1;
                    if(type==0){
                        root=q;
                        root->parent=NULL;
                    }
                    else if(type==1)
                        pp->leftchild=q;
                    else
                        pp->rightchild=q;
                }
            }
            deleteLeaf(p);
        }
        else if(p->color==-1){ //黑色
            if(p->leftchild&&!p->rightchild){ //只有左孩子,把孩子换上来
                if(type==0){
                    root=p->leftchild;
                    root->parent=NULL;
                }
                else if(type==2){
                    pp->rightchild=p->leftchild;
                    p->leftchild->parent=pp;
                }
                else {
                    pp->leftchild=p->leftchild;
                    p->leftchild->parent=pp;
                }
                p->leftchild->color=-1;
            }
            else if(p->rightchild&&!p->leftchild){ //只有右孩子,把孩子换上来
                if(type==0){
                    root=p->rightchild;
                    root->parent=NULL;
                }
                else if(type==2){
                    pp->rightchild=p->rightchild;
                    p->rightchild->parent=pp;
                }
                else {
                    pp->leftchild=p->rightchild;
                    p->rightchild->parent=pp;
                }
                p->rightchild->color=-1;
            }
            else{ //有两个孩子
                while(p->leftchild&&p->rightchild){
                    pp=p->parent;
                    if(!pp)
                        type=0;
                    else if(pp->leftchild==p)
                        type=1;
                    else
                        type=2;
                    treeNode<T> *q=p->leftchild;
                    treeNode<T> *c=p->rightchild;
                    p->leftchild=q->leftchild;
                    p->rightchild=q->rightchild;
                    if(q->leftchild)
                        q->leftchild->parent=p;
                    if(q->rightchild)
                        q->rightchild->parent=p;
                    q->rightchild=c;
                    c->parent=q;
                    q->leftchild=p;
                    q->parent=p->parent;
                    p->parent=q;
                    q->color=p->color;
                    if(type==0){
                        root=q;
                        root->parent=NULL;
                    }
                    else if(type==1)
                        pp->leftchild=q;
                    else
                        pp->rightchild=q;
                }
                deleteLeaf(p);
            }
        }
        return *this;
    }
    bsTree<T>& deleteLeaf(treeNode<T> *t){
        treeNode<T> *p=t;
        treeNode<T> *pp=p->parent;
        int type;
        if(!pp)
            type=0;
        else if(pp->leftchild==p)
            type=1;
        else
            type=2;
        if(p->color==1){ //红色
            if(type==2)
                pp->rightchild=NULL;
            else
                pp->leftchild=NULL;
        }
        else if(p->color==-1){ //黑色
            if(type==0){ //p没有孩子也没有父亲,删除后树为空
                root=NULL;
            }
            //兄弟一定存在
            else if(type==1){ //p是pp的左孩子
                treeNode<T> *ppp=pp->parent;
                if(!ppp)
                    type=0;
                else if(ppp->leftchild==pp)
                    type=1;
                else
                    type=2;
                if(pp->rightchild->color==1){ //兄弟是红色
                    pp=xybRR(pp); //旋转,兄弟变黑
                    if(type==0)
                        root=pp;
                    else if(type==1)
                        ppp->leftchild=pp;
                    else
                        ppp->rightchild=pp;
                    deleteLeaf(p);
                }
                else{ //兄弟是黑色
                    pp->leftchild=NULL;
                    if(pp->rightchild->rightchild){ //右侄子存在,一定是红色
                        pp=xybRR(pp);
                        pp->rightchild->color=-1;
                        if(type==0)
                            root=pp;
                        else if(type==1)
                            ppp->leftchild=pp;
                        else
                            ppp->rightchild=pp;
                    }
                    else if(pp->rightchild->leftchild){ //左侄子存在,一定是红色
                        treeNode<T> *b=pp->rightchild;
                        b=xybLL(b);
                        pp->rightchild=b;
                        //变成了右侄子
                        pp=xybRR(pp);
                        pp->rightchild->color=-1;
                        if(type==0)
                            root=pp;
                        else if(type==1)
                            ppp->leftchild=pp;
                        else
                            ppp->rightchild=pp;
                    }
                    else if(pp->color==1){ //父节点是红色,兄弟没有孩子
                        pp->color=-1;
                        pp->rightchild->color=1;
                    }
                    else{ //父节点是黑色,兄弟是黑色,兄弟没有孩子
                        pp->rightchild->color=1;
                    }
                }
            }
            else{ //p是pp的右孩子
                treeNode<T> *ppp=pp->parent;
                if(pp->leftchild->color==1) { //兄弟是红色
                    pp=xybLL(pp); //旋转,兄弟变黑
                    if(type==0)
                        root=pp;
                    else if(type==1)
                        ppp->leftchild=pp;
                    else
                        ppp->rightchild=pp;
                    deleted(p->data);
                }
                else{ //兄弟是黑色
                    pp->rightchild=NULL;
                    if(pp->leftchild->leftchild){ //左侄子存在,一定是红色
                        pp=xybLL(pp);
                        pp->leftchild->color=-1;
                        if(type==0)
                            root=pp;
                        else if(type==1)
                            ppp->leftchild=pp;
                        else
                            ppp->rightchild=pp;
                    }
                    else if(pp->leftchild->rightchild){ //右侄子存在,一定是红色
                        treeNode<T> *b=pp->leftchild;
                        b=xybLL(b);
                        pp->leftchild=b;
                        //变成了左侄子
                        pp=xybLL(pp);
                        pp->leftchild->color=-1;
                        if(type==0)
                            root=pp;
                        else if(type==1)
                            ppp->leftchild=pp;
                        else
                            ppp->rightchild=pp;
                    }
                    else if(pp->color==1){ //父节点是红色,兄弟没有孩子
                        pp->color=-1;
                        pp->leftchild->color=1;
                    }
                    else{ //父节点是黑色,兄弟是黑色,兄弟没有孩子
                        pp->leftchild->color=1;
                    }
                }
            }
        }
        return *this;
    }
    void ascend(treeNode<T> *t){
        if(t->leftchild)
            ascend(t->leftchild);
        cout<<t->data<<" ";
        if(t->rightchild)
            ascend(t->rightchild);
    }
    treeNode<T>* getRoot(){
        return root;
    }
private:
    treeNode<T> *root;
};


int main(){
    redBlackTree<int> rbt;
    int t;
    cout<<"Please input 10 integers!"<<endl;
    for(int i=0;i<10;i++){
        cin>>t;
        rbt.insert(t);
    }
    cout<<"Red-black tree in ascending order:"<<endl;
    rbt.ascend(rbt.getRoot());
    cout<<endl<<"Please input 5 integers you want to delete!"<<endl;
    for(int i=0;i<5;i++){
        cin>>t;
        rbt.deleted(t);
    }
    cout<<"Red-black tree in ascending order:"<<endl;
    rbt.ascend(rbt.getRoot());
    cout<<endl;
    return 0;
}

 插入后:

删除后:

 有重复值的红黑树描述

//50 60 65 80 10 62 70 70 23 13
//13 50 70 10 80
//和无重复值的红黑树描述类似,只修改了以下部分

treeNode<T>* find(const T& t) {
    treeNode<T> *p=root,*pp=NULL; //p为应该插入的位置,pp为p的父节点
    while(p){
        pp=p;
        if(t<p->data) //如果关键值比当前节点的关键值小,进入左子树
            p=p->leftchild;
        else //如果关键值比当前节点的关键值大,进入右子树
            p=p->rightchild;
    }
    return pp;
}

bsTree<T>& insert(const T& t) {
    treeNode<T> *p=find(t); //找到应该插入的位置的父节点
    treeNode<T> *q=new treeNode<T>; //新建节点
    q->data=t;
    q->parent=p;
    q->color=1;
    if(!p){ //如果父节点为空,说明树为空
        q->color=-1;
        root=q;
        return *this;
    }
    if(t<p->data) //如果关键值小于父节点的值
        p->leftchild=q;
    else //如果关键值大于父节点的值
        p->rightchild=q;
    //……
}

 bsTree<T>& deleted(const T& t){
    treeNode<T> *c=root,*cp=NULL; //p为应该插入的位置,pp为p的父节点
    while(c){
        cp=c;
        if(t<c->data) //如果关键值比当前节点的关键值小,进入左子树
            c=c->leftchild;
        else if(t>c->data)//如果关键值比当前节点的关键值大,进入右子树
            c=c->rightchild;
        else
            break;
    }
    treeNode<T> *p=cp;
    if(!p||p->data!=t){
        return *this;
    }
    else{
        //……
    }
    deleted(t);
    return *this;
}

插入后:

删除后:

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值