zoukankan      html  css  js  c++  java
  • 04-树5 Root of AVL Tree + AVL树操作集

      An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

         

         

    Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

    Input Specification:

    Each input file contains one test case. For each case, the first line contains a positive integer NN (le 2020) which is the total number of keys to be inserted. Then NN distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

    Output Specification:

    For each test case, print the root of the resulting AVL tree in one line.

    Sample Input 1:

    5
    88 70 61 96 120
    

    Sample Output 1:

    70

    /*!
     * file 04-树5 Root of AVL Tree.cpp
     *
     * author ranjiewen
     * date 2017/04/01 18:54
     *
     * 
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct AVLNode *Position;
    typedef Position AVLTree;
    typedef int ElementType;
    struct AVLNode{
        ElementType Data;
        AVLTree Left;
        AVLTree Right;
        int Height;  //树高
    };
    
    int Max(int a, int b)
    {
        return a > b ? a : b;
    }
    
    //可将程序中用到的GetTreeHeight()替换掉
    int GetHeight(Position p)
    {
        if (!p)
            return -1;
        return p->Height;
    }
    
    int GetTreeHeight(AVLTree T)
    {
        int HL = 0, HR = 0;
        int Max_H = 0;
        if (T)
        {
            if (T->Left)
            {
                HL = GetTreeHeight(T->Left);
            }
            if (T->Right)
            {
                HR = GetTreeHeight(T->Right);
            }
            Max_H = (HL > HR) ? (HL + 1) : (HR + 1);
        }
        return  Max_H;
    }
    
    AVLTree SingleLeftRotation(AVLTree A)
    {
        //A必须有一个左子结点B
        //将A与B做左单旋,更新A,B的高度,返回新的根节点B
        AVLTree B = A->Left;
        A->Left = B->Right;
        B->Right = A;
        A->Height = Max(GetTreeHeight(A->Left), GetTreeHeight(A->Right)) + 1;
        B->Height = Max(GetTreeHeight(B->Left), A->Height) + 1;
        return B;
    }
    
    AVLTree SingleRightRotation(AVLTree A)
    {
        //A必须有一个右子节点B
        //将A,B做右单旋,更新A,B的高度,返回新的根节点B
        AVLTree B = A->Right;
        A->Right = B->Left;
        B->Left = A;
        A->Height = Max(GetTreeHeight(A->Left),GetTreeHeight(A->Right))+1;
        B->Height = Max(GetTreeHeight(B->Right), A->Height) + 1;
    
        return B;
    }
    
    AVLTree DoubleLeftRightRotation(AVLTree A)
    {
        //A必须有一个左子节点B,且B必须有一个右子节点C
        //将A,B与C做两次单旋,返回新的根节点C
        
        //将B,C做右单旋,C被返回
        A->Left = SingleRightRotation(A->Left);
        //将A与C做左单旋,C被返回
        return SingleLeftRotation(A);
    }
    
    AVLTree DoubleRightLeftRotation(AVLTree A)
    {
        //A必须有一个右子节点B,且B必须有一个左子节点C
        
        //将B,C做左单旋,C被返回
        A->Right = SingleLeftRotation(A->Right);
        //将A,C做右单旋,C被返回
        return SingleRightRotation(A);
    }
    
    //将x插入到AVL树中,并且返回调整后的AVL树
    AVLTree Insert(AVLTree T, ElementType x)
    {
        if (!T)
        {
            //若为空树,则新建包含一个结点的树
            T = (AVLTree)malloc(sizeof(struct AVLNode));
            T->Data = x;
            T->Left = T->Right = NULL;
            T->Height = 0;
        }
        else if (x<T->Data)
        {
            //插入T的左子树
            T->Left = Insert(T->Left,x);
            //如果需要左旋
            if (GetTreeHeight(T->Left)-GetTreeHeight(T->Right)==2)
            {
                if (x < T->Left->Data) //需要左单旋
                {
                    T = SingleLeftRotation(T);
                }
                else
                    T = DoubleLeftRightRotation(T); //左-右双旋
            }
        }
        else if (x>T->Data)
        {
            T->Right = Insert(T->Right,x);
            //如果需要右旋
            if (GetTreeHeight(T->Left)-GetTreeHeight(T->Right)==-2)
            {
                if (x>T->Right->Data) //右单旋
                {
                    T = SingleRightRotation(T);
                }
                else
                {
                    T = DoubleRightLeftRotation(T); //右-左双旋
                }
            }
        }
        // else x==T->Data 无需插入
        
        //别忘了更新树高
        T->Height = Max(GetTreeHeight(T->Left), GetTreeHeight(T->Right)) + 1;
        return T;
    }
    
    static int FindMin(AVLTree T){
        if (T == NULL){
            return -1;
        }
        while (T->Left != NULL){
            T = T->Left;
        }
        return T->Data;
    }
    
    //返回-1表示,树中没有该数据,删除失败,
    int Delete(AVLTree *T, ElementType D){ //指针的指针
        static Position tmp;
        if (*T == NULL){
            return -1;
        }
        else{
            //找到要删除的节点
            if (D == (*T)->Data){
                //删除的节点左右子支都不为空,一定存在前驱节点
                if ((*T)->Left != NULL && (*T)->Right != NULL){
    
                    D = FindMin((*T)->Right);//找后继替换
                    (*T)->Data = D;
                    Delete(&(*T)->Right, D);//然后删除后继节点,一定成功
    
                    //在右子支中删除,删除后有可能左子支比右子支高度大2
                    if (GetHeight((*T)->Left) - GetHeight((*T)->Left) == 2){
                        //判断哪一个左子支的的两个子支哪个比较高
                        if (GetHeight((*T)->Left->Left) >= GetHeight((*T)->Left->Right)){
                            *T=SingleRightRotation(*T);
                        }
                        else{
                            *T = DoubleLeftRightRotation(*T);
                            /*LeftRotate(&(*T)->left);
                            RightRotate(T);*/
                        }
                    }
                }
                else
                if ((*T)->Left == NULL){//左子支为空
                    tmp = (*T);
                    (*T) = tmp->Right;
                    free(tmp);
                    return 0;
                }
                else
                if ((*T)->Right == NULL){//右子支为空
                    tmp = (*T);
                    (*T) = tmp->Right;
                    free(tmp);
                    return 0;
                }
            }
            else
            if (D > (*T)->Data){//在右子支中寻找待删除的节点
                if (Delete(&(*T)->Right, D) == -1){
                    return -1;//删除失败,不需要调整,直接返回
                }
                if (GetHeight((*T)->Left) - GetHeight((*T)->Right) == 2){
                    if (GetHeight((*T)->Left->Left) >= GetHeight((*T)->Left->Right)){
                        *T=SingleRightRotation(*T);
                    }
                    else{
                        *T = DoubleLeftRightRotation(*T);
                        /*LeftRotate(&(*T)->left);
                        RightRotate(T);*/
                    }
                }
            }
            else
            if (D < (*T)->Data){//在左子支中寻找待删除的节点
                if (Delete(&(*T)->Left, D) == -1){
                    return -1;
                }
                if (GetHeight((*T)->Right) - GetHeight((*T)->Right) == 2){
                    if (GetHeight((*T)->Right->Right) >= GetHeight((*T)->Right->Left)){
                        *T=SingleLeftRotation(*T);
                    }
                    else{
                        *T = DoubleRightLeftRotation(*T);
                        /*RightRotate(&(*T)->right);
                        LeftRotate(T);*/
                    }
                }
            }
        }
        //更新当前节点的高度
        (*T)->Height = Max(GetHeight((*T)->Left), GetHeight((*T)->Right)) + 1;
        //printf("%d
    ", (*T)->Data);
        return 0;
    }
    
    int main()
    {
        int N,data;
        AVLTree root=nullptr;
        scanf("%d", &N);
        for (int i = 0; i < N;i++)
        {
            scanf("%d", &data);
            root = Insert(root, data);
        }
        printf("%d
    ",root->Data);
    
        Delete(&root, 70);
        printf("%d
    ", root->Data);
    
        return 0;
    }
    AVL树原理及实现 +B树

     
  • 相关阅读:
    javaScript真值和假值以及相等操作符
    javaScript操作符
    javascript变量作用域
    javaScript变量
    Linux命令学习之路——档案拷贝:cp
    Linux命令学习之路——变更文档拥有者:chown
    Linux命令学习之路——文档权限管理:chmod
    Linux命令学习之路——变更工作目录:cd
    关于Scrum团队的理解
    关于MATHAPP的测试
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/6657964.html
Copyright © 2011-2022 走看看