浙大数据结构第四周之04-树5 Root of AVL Tree

题目详情:

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 N (≤20) which is the total number of keys to be inserted. Then N 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

Sample Input 2:

7
88 70 61 96 120 90 65

Sample Output 2:

88

简单翻译:

就是给一个二叉平衡树的插入序列,依据这个序列构建二叉平衡树,并返回根节点

主要思路:

用插入法构建,即需要在程序里实现左右单旋与左右双旋

要特别注意的是,如果插入一个节点导致树不平衡了,我们要找到从下往上第一个不平衡的地方进行调整,调整完整个树就平衡了,而不是说要返回到最上面进行调整。

举个列子

假设我们在递归的过程中,输入AVLTree是NULL,也就是如下情况:

15这里是一定平衡的(左右都是空),返回给11,11这里肯定也是平衡的,返回给9,但9就不是平衡的了

然后就可以判断让9恢复平衡应该进行哪种操作,即RR还是RL,这里判断为RR。

调整完以后,再返回到9的父节点,这个时候9的父节点再进行判断,以此类推。

第一次写错误:

(1)对树的高度的把握,准确求出树高是旋转的关键,本题实现是直接存储在树节点中,通过直接访问节点与计算左右子树高度最大值再加1求得当前节点高度

在每次旋转后都需要求出两个"交换位置"节点的各自树高

插入操作最后再求当前节点树高

(2)

左旋:根节点与左孩子"交换"位置,左孩子右子树挂到根节点左子树

右旋:根节点与右孩子"交换"位置,右孩子左子树挂到根节点右子树

左-右双旋:先根节点左孩子与它的右孩子右旋,再根节点与现在的左孩子左旋

右-左双旋:先根节点右孩子与它的左节点左旋,再根节点与现在的右孩子右旋

代码实现:

/*
定义树的数据结构,其中每个节点保存以当前节点为root的子树高度
读入数据
插入节点以建树
左旋(1)左单旋(2)左-右双旋
右旋(1)右单旋(2)右-左双旋
*/
#include <stdio.h>
#include <stdlib.h>
/*定义树的数据结构*/
typedef struct TreeNode TreeNode;
typedef TreeNode* Position;
typedef Position AVLTree;
struct TreeNode {
    int Data;
    Position Leftchild;
    Position Rightchild;
    int Height;
};
/*获取树的高度*/
int Max(int a, int b) {
    return a > b ? a : b;
}
int GetTreeHeight(Position root) { 
    if(root == NULL) {
        return 0;
    }
    else return root->Height;
}
/*每次旋转后都要重新获取以当前节点为根节点的子树高度*/
/*左单旋*/
Position SingleLeftRotation(Position root) {
    Position initialRoot = root;
    Position newRoot = root->Leftchild;
    root->Leftchild = root->Leftchild->Rightchild;
    newRoot->Rightchild = initialRoot;
    newRoot->Height = Max(GetTreeHeight(newRoot->Leftchild), GetTreeHeight(newRoot->Rightchild)) + 1;
    initialRoot->Height = Max(GetTreeHeight(initialRoot->Leftchild), GetTreeHeight(initialRoot->Rightchild)) + 1;
    return newRoot;
}
/*右单旋*/
Position SingleRightRotation(Position root) {
    Position initialRoot = root;
    Position newRoot = root->Rightchild;
    root->Rightchild = root->Rightchild->Leftchild;
    newRoot->Leftchild = initialRoot;
    initialRoot->Height = Max(GetTreeHeight(initialRoot->Leftchild), GetTreeHeight(initialRoot->Rightchild)) + 1;
    newRoot->Height = Max(GetTreeHeight(newRoot->Leftchild), GetTreeHeight(newRoot->Rightchild)) + 1;
    return newRoot;
}
/*左-右双旋*/
Position DoubleLeftRightRotation(Position root) {
    root->Leftchild = SingleRightRotation(root->Leftchild);
    return SingleLeftRotation(root);
}
/*右-左双旋*/
Position DoubleRightLeftRotation(Position root) {
    root->Rightchild = SingleLeftRotation(root->Rightchild);
    return SingleRightRotation(root);
}
/*插入节点*/
Position Insert(Position root, int data) {
    if(root == NULL) {
        root = (Position)malloc(sizeof(TreeNode));
        root->Data = data;
        root->Leftchild = root->Rightchild = NULL;
        root->Height = 1;
        return root;
    }

    if(root->Data > data) {
        root->Leftchild = Insert(root->Leftchild, data);
        if(GetTreeHeight(root->Leftchild) - GetTreeHeight(root->Rightchild) > 1) {
            if(root->Leftchild->Data > data) {  //左单旋
                root = SingleLeftRotation(root);
            }
            else {  //左-右双旋
                root = DoubleLeftRightRotation(root);
            }
        }
    }   
    else if(root->Data < data) {
        root->Rightchild = Insert(root->Rightchild, data);
        if(GetTreeHeight(root->Rightchild) - GetTreeHeight(root->Leftchild) > 1) {
            if(root->Rightchild->Data < data) {
                root = SingleRightRotation(root);
            }
            else {
                root = DoubleRightLeftRotation(root);
            }
        }
    }

    root->Height = Max(GetTreeHeight(root->Leftchild), GetTreeHeight(root->Rightchild)) + 1;

    return root;
}

void DeleteTree(AVLTree root) {
    if(root == NULL) {
        return;
    }

    DeleteTree(root->Leftchild);
    DeleteTree(root->Rightchild);
    free(root);
    return;
}

/*建树*/
int BuildTree() {
    int N;
    scanf("%d", &N);
    AVLTree root = NULL;
    for(int i = 0; i < N; i++) {
        int data;
        scanf("%d", &data);
        root = Insert(root, data);
    }
    int ret = root->Data;
    DeleteTree(root);
    return ret;
}

int main() {
    int root = BuildTree();
    printf("%d", root);
    return 0;
}

参考文章

相关推荐
ChoSeitaku1 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程1 小时前
双向链表专题
数据结构
香菜大丸1 小时前
链表的归并排序
数据结构·算法·链表
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
@小博的博客1 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
泉崎3 小时前
11.7比赛总结
数据结构·算法
你好helloworld3 小时前
滑动窗口最大值
数据结构·算法·leetcode
JSU_曾是此间年少4 小时前
数据结构——线性表与链表
数据结构·c++·算法
sjsjs115 小时前
【数据结构-合法括号字符串】【hard】【拼多多面试题】力扣32. 最长有效括号
数据结构·leetcode
blammmp5 小时前
Java:数据结构-枚举
java·开发语言·数据结构