首页 > 其他 > 详细

AVL树

时间:2020-07-28 22:07:30      阅读:59      评论:0      收藏:0      [点我收藏+]
//bf=右子树-左子树,删除时用左子树的中序最后一个结点填充
#include<iostream>
#include<stack>
#include<queue>
using namespace std;

struct Node{
    int bf;
    int data;
    Node* left;
    Node* right;
    Node():bf(0),left(NULL),right(NULL){}
};
void RR(Node* &ptr){  //左单旋转
    Node* subL=ptr;
    ptr=ptr->right;
    subL->right=ptr->left;
    ptr->left=subL;
    ptr->bf=subL->bf=0;
}
void LL(Node* &ptr){  //右单旋转
    Node* subR=ptr;
    ptr=ptr->left;
    subR->left=ptr->right;
    ptr->right=subR;
    ptr->bf=subR->bf=0;
}
void LR(Node* &ptr){  //先左后右双旋转
    Node *subR=ptr, *subL=ptr->left;
    ptr=ptr->left->right;
    subL->right=ptr->left;
    ptr->left=subL;
    if(ptr->bf==-1||ptr->bf==0) subL->bf=0; //ptr->bf值可能为-1或0
    else subL->bf=-1;
    subR->left=ptr->right;
    ptr->right=subR;
    if(ptr->bf==-1) subR->bf=1;
    else subR->bf=0;
    ptr->bf=0;
}
void RL(Node* &ptr){  //先右后左双旋转
    Node *subL=ptr,*subR=ptr->right;
    ptr=ptr->right->left;
    subR->left=ptr->right;
    ptr->right=subR;
    if(ptr->bf==1||ptr->bf==0) subR->bf=0;  //ptr->bf值可能为1或0
    else subR->bf=1;
    subL->right=ptr->left;
    ptr->left=subL;
    if(ptr->bf==1) subL->bf=-1;
    else subL->bf=0;
    ptr->bf=0;
}
bool Insert(Node* &ptr,int el){
    Node *pre=NULL, *p=ptr, *ppre;  //ptr指针记录根节点
    stack<Node*> st;
    while(p!=NULL){
        if(el==p->data) return false;
        pre=p;
        st.push(pre);
        if(el<p->data) p=p->left;
        else p=p->right;
    }
    p=new Node();
    p->data=el;
    if(pre==NULL){
        ptr=p;
        return true;
    }
    if(el<pre->data) pre->left=p;
    else pre->right=p;
    while(!st.empty()){
        pre=st.top();
        st.pop();
        if(p==pre->left) pre->bf--; //平衡因子的更新
        else pre->bf++;             //平衡因子的更新
        if(pre->bf==0) break;
        if(pre->bf==1||pre->bf==-1) p=pre;
        else{
            if(pre->bf*p->bf>0){    //同号,单旋转
                if(pre->bf==-2) LL(pre);
                else RR(pre);
            }else{                  //异号,双旋转
                if(pre->bf==-2) LR(pre);
                else RL(pre);
            }
            break;
        }
    }
    if(st.empty()){
        ptr=pre;
    }else{
        ppre=st.top();
        if(pre->data<ppre->data) ppre->left=pre;
        else ppre->right=pre;
    }
    return true;
}
bool Remove(Node* &ptr,int x)
{
    Node *pre=NULL, *p=ptr, *temp, *ppre;
    stack<Node*> st;
    while(p!=NULL)      //寻找删除位置
    {
        if(x==p->data) break;    //找到等于x的结点p,停止搜索
        pre=p;
        st.push(pre);   //否则用栈记忆查找路径
        if(x<p->data) p=p->left;
        else p=p->right;
    }
    if(p==NULL) return false;    //未找到被删除结点,删除失败
    if(p->left!=NULL&&p->right!=NULL)     //被删除结点有两个子女
    {
        pre=p;
        st.push(pre);
        temp=p->left;   //在p左子树找p的直接前驱
        while(temp->right!=NULL)
        {
            pre=temp;
            st.push(pre);
            temp=temp->right;
        }
        p->data=temp->data;     //用temp的值填补p
        p=temp;         //被删结点转化为temp,使p指向temp
    }
    if(p->left!=NULL) temp=p->left;      //被删结点p只有一个子女q
    else temp=p->right;
    if(pre==NULL) ptr=temp;     //被删结点为根节点,当真正删除的结点为根结点时,那表明这个树就这一个结点,ptr=NULL
    else                //被删结点不是根结点
    {
        if(pre->left==p) pre->left=temp;  //连接,此后temp完成删除后子女链接的使命
        else pre->right=temp;
        while(!st.empty())      //重新平衡化
        {
            pre=st.top();
            st.pop();           //从栈中退出父结点
            if(pre->right==temp) pre->bf--;    //调整父结点的平衡因子
            else pre->bf++;
            if(pre->bf==0) temp=pre;           //  |bf|=0
            if(pre->bf==1||pre->bf==-1) break; //  |bf|=1
            if(pre->bf==2||pre->bf==-2)        //  |bf|=2
            {
                if(pre->bf=-2) temp=pre->left; //用temp指向较高的子树
                else temp=pre->right;          //用temp指向较高的子树
                if(temp->bf==0)
                {
                    if(pre->bf=-2)
                    {
                        LL(pre);   //右单旋转,但把pre->bf=pre->left->bf=0了,下面需要值重置
                        pre->bf=1;
                        pre->left->bf=-1;
                    }
                    else
                    {
                        RR(pre);   //左单旋转,但把pre->bf=pre->left->bf=0了,下面需要值重置
                        pre->bf=-1;
                        pre->right->bf=1;
                    }
                    break;
                }
                if(temp->bf * pre->bf > 0)      //两结点平衡因子同号
                {
                    if(pre->bf==-2) LL(pre);    //右单旋转
                    else RR(pre);   //左单旋转
                }
                else       //两结点平衡因子反号
                {
                    if(pre->bf==-2) LR(pre);    //先左后右双旋转, " < "型
                    else RL(pre);   //先右后左双旋转," > "型
                }
            }
        }
        if(st.empty()) {   //旋转后与上层链接
            ptr=pre;
        }else{
            ppre=st.top();
            if(pre->data<ppre->data) ppre->left=pre;
            else ppre->right=pre;
        }
    }
    delete p;
    return true;
}
void LevelTraversal(Node* ptr){
    queue<Node*> Q;
    Node* p=NULL;
    Q.push(ptr);
    while(!Q.empty()){
        p=Q.front();
        cout<<p->data<<" "<<p->bf<<endl;
        Q.pop();
        if(p->left!=NULL){
            Q.push(p->left);
        }
        if(p->right!=NULL){
            Q.push(p->right);
        }
    }
}
int main(){
    Node* root=NULL;
    int arr[]={16,3,7,11,9,26,18,14,15};
    for(int i=0;i<sizeof(arr)/sizeof(int);i++){
        Insert(root,arr[i]);
    }
    LevelTraversal(root);//结果应为:11 7 18 3 9 15 26 14 16
    cout<<endl;
    Remove(root,16);
    LevelTraversal(root);
    cout<<endl;
    return 0;
}
//11 1
//7 0
//18 -1
//3 0
//9 0
//15 0
//26 0
//14 0
//16 0
//
//11 1
//7 0
//18 -1
//3 0
//9 0
//15 -1
//26 0
//14 0

 

AVL树

原文:https://www.cnblogs.com/zzyf/p/13392459.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!