浙大数据结构第四周之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;
}

参考文章

相关推荐
strive-debug1 小时前
上篇:《排序算法的奇妙世界:如何让数据井然有序?》
数据结构·算法·排序算法
PHASELESS4111 小时前
Java堆结构深度解析:原理、实现与应用全指南
java·开发语言·数据结构
杀神lwz2 小时前
数据结构和算法(六)--栈&队列&堆
数据结构
ん贤2 小时前
图论基础理论
c语言·数据结构·c++·算法·图论
小哲会魔法3 小时前
冒泡排序、插入排序、快速排序、堆排序、希尔排序、归并排序
数据结构·算法·排序算法
Dreams_l4 小时前
顺序表(Arraylist)和链表(Linkedlist)
数据结构·链表
Dominic_Holmes5 小时前
代码随想录算法训练营Day30 | 01背包问题(卡码网46. 携带研究材料)、Leetcode416.分割等和子集
数据结构·python·算法·leetcode
Dovis(誓平步青云)9 小时前
【数据结构】励志大厂版·初阶(复习+刷题):线性表(顺序表)
c语言·数据结构·经验分享·笔记·学习·算法·学习方法
Brookty10 小时前
【算法】归并排序
数据结构·算法·排序算法
星星火柴93612 小时前
数据结构:哈希表 | C++中的set与map
数据结构·c++·笔记·算法·链表·哈希算法·散列表