对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是O(logN),而接近O(N),这样将大大减少对树的查找效率。一种解决办法就是要有一个称为平衡的附加的结构条件:任何节点的深度均不得过深。有一种最古老的平衡查找树,即AVL树。

  AVL树是带有平衡条件的二叉查找树。平衡条件是每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1)。相比于普通的二叉树,AVL树的节点需要增加一个变量保存节点高度。AVL树的节点声明如下:

typedef struct TreeNode *AvlTree;
typedef struct TreeNode *Position;
struct TreeNode
{
int Data;
AvlTree Left;
AvlTree Right;
int Height; //保存节点高度
};

  只有一个节点的树显然是AVL树,之后我们向其插入节点。然而在插入过程中可能破坏AVL树的特性,因此我们需要对树进行简单的修正,即AVL树的旋转。

  设a节点在插入下一个节点后会失去平衡,这种插入可能出现四种情况:

  1. 对a的左儿子的左子树进行一次插入。(左-左)

  2. 对a的左儿子的右子树进行一次插入。(左-右)

  3. 对a的右儿子的左子树进行一次插入。(右-左)

  4. 对a的右儿子的右子树进行一次插入。(右-右)

  情形1和4,情形2和3分别是关于A节点的镜像对称,故在理论上是两种情况,而编程具体实现还是需要考虑四种。

  单旋转--情形1和4:

  双旋转--情形2和3:

  情形2和3就是向上图中的子树Y插入一个节点,由上图可知,无论是左单旋还是右单旋都无法改变子树Y的高度。解决办法是再将子树Y分解成根节点和相应的左子树和右子树,然后对相应的节点做相应的旋转,如下图:

  下面一个题即是考察AVL树的旋转:题目来源:http://www.patest.cn/contests/mooc-ds/04-%E6%A0%914

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 ythe 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

题目大意是先输入一个整数N,然后依次输入N个节点的值,以此建立AVL树,最后输出AVL树的根节点的值。

代码如下:

#include <cstdio>
#include <cstdlib> typedef struct TreeNode *AvlTree;
typedef struct TreeNode *Position;
struct TreeNode
{
int Data;
AvlTree Left;
AvlTree Right;
int Height;
}; AvlTree Insert(int x, AvlTree T); //插入新节点,必要时调整
Position SingleRotateWithLeft(Position a); //左单旋
Position SingleRotateWithRight(Position b); //右单旋
Position DoubleRotateWithLeft(Position a); //左右旋
Position DoubleRotateWithRight(Position b); //右左旋 int Max(int x1, int x2); //返回两个int中较大的
int Height(Position P); //返回一个节点的高度 int main()
{
int n, x;
AvlTree T = NULL; scanf("%d", &n);
for (int i = ; i < n; i++)
{
scanf("%d", &x);
T = Insert(x, T);
}
printf("%d\n", T->Data); //打印根节点的值 return ;
} AvlTree Insert(int x, AvlTree T)
{
if (T == NULL)
{
T = (AvlTree)malloc(sizeof(struct TreeNode));
T->Data = x;
T->Left = T->Right = NULL;
T->Height = ;
}
else if (x < T->Data) //向左子树插入
{
T->Left = Insert(x, T->Left);
if (Height(T->Left) - Height(T->Right) == ) //需调整
{
if (x < T->Left->Data)
T = SingleRotateWithLeft(T);
else
T = DoubleRotateWithLeft(T);
}
}
else if (x > T->Data) //向右子树插入
{
T->Right = Insert(x, T->Right);
if (Height(T->Right) - Height(T->Left) == ) //需调整
{
if (x > T->Right->Data)
T = SingleRotateWithRight(T);
else
T = DoubleRotateWithRight(T);
}
}
/*else值为x的节点已经存在树中,无需插入*/ /*更新节点高度*/
T->Height = Max(Height(T->Left), Height(T->Right)) + ;
return T;
} Position SingleRotateWithLeft(Position a)
{
Position b = a->Left;
a->Left = b->Right;
b->Right = a;
//更新a, b节点高度
a->Height = Max(Height(a->Left), Height(a->Right)) + ;
b->Height = Max(Height(b->Left), Height(b->Right)) + ; return b; /*新的根节点*/
} Position SingleRotateWithRight(Position b)
{
Position a = b->Right;
b->Right = a->Left;
a->Left = b;
//更新a,b节点高度
a->Height = Max(Height(a->Left), Height(a->Right)) + ;
b->Height = Max(Height(b->Left), Height(b->Right)) + ;
return a; /*新的根节点*/
} Position DoubleRotateWithLeft(Position a)
{
a->Left = SingleRotateWithRight(a->Left);
return SingleRotateWithLeft(a);
} Position DoubleRotateWithRight(Position b)
{
b->Right = SingleRotateWithLeft(b->Right);
return SingleRotateWithRight(b);
} int Max(int x1, int x2)
{
return (x1 > x2) ? x1 : x2;
} int Height(Position P)
{
if (P == NULL) //空节点高度为-1
return -;
return P->Height;
}

  需要注意的细节是我们需要快速得到一个节点(包括空节点)的高度,所以我们需要些一个函数来处理空节点(空指针)的情况,而不是简单的Position->Height。

  

04-树4. Root of AVL Tree-平衡查找树AVL树的实现的更多相关文章

  1. 【PAT甲级】1066 Root of AVL Tree (25 分)(AVL树建树模板)

    题意: 输入一个正整数N(<=20),接着输入N个结点的值,依次插入一颗AVL树,输出最终根结点的值. AAAAAccepted code: #define HAVE_STRUCT_TIMESP ...

  2. 详解平衡二叉树(AVL tree)平衡操作(图+代码)

    * 左左就右旋,右右就左旋 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int max ...

  3. PAT甲级1066. Root of AVL Tree

    PAT甲级1066. Root of AVL Tree 题意: 构造AVL树,返回root点val. 思路: 了解AVL树的基本性质. AVL树 ac代码: C++ // pat1066.cpp : ...

  4. PTA 04-树5 Root of AVL Tree (25分)

    题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/668 5-6 Root of AVL Tree   (25分) An AVL tree ...

  5. PAT 甲级 1066 Root of AVL Tree (25 分)(快速掌握平衡二叉树的旋转,内含代码和注解)***

    1066 Root of AVL Tree (25 分)   An AVL tree is a self-balancing binary search tree. In an AVL tree, t ...

  6. PAT甲级1123. Is It a Complete AVL Tree

    PAT甲级1123. Is It a Complete AVL Tree 题意: 在AVL树中,任何节点的两个子树的高度最多有一个;如果在任何时候它们不同于一个,则重新平衡来恢复此属性.图1-4说明了 ...

  7. HDU 2193 AVL Tree

    AVL Tree An AVL tree is a kind of balanced binary search tree. Named after their inventors, Adelson- ...

  8. 数据结构和算法(Golang实现)(28)查找算法-AVL树

    AVL树 二叉查找树的树高度影响了查找的效率,需要尽量减小树的高度,AVL树正是这样的树. 一.AVL树介绍 AVL树是一棵严格自平衡的二叉查找树,1962年,发明者Adelson-Velsky和La ...

  9. 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树

    某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...

  10. PAT Advanced 1066 Root of AVL Tree (25) [平衡⼆叉树(AVL树)]

    题目 An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child ...

随机推荐

  1. 《图解 HTTP 》阅读 —— 第三章

    第3章 HTTP 报文内的 HTTP 信息 用于 HTTP 协议交互的信息称为 HTTP 报文:请求报文和响应报文 HTTP 在传输数据时通过编码可以提升速率,能有效的处理大量数据,但是会消耗更多的C ...

  2. grunt requireJS 的基础配置

    module.exports = function(grunt){ //grunt的配置我就不叨叨了 自己看官网就ok了 //我就介绍下grunt的依赖插件grunt-contrib-requirej ...

  3. 152.[LeetCode] Maximum Product Subarray

    Given an integer array nums, find the contiguous subarray within an array (containing at least one n ...

  4. Machine Learning方法总结

    Kmeans——不断松弛(?我的理解)模拟,将点集分成几堆的算法(堆数需要自己定). 局部加权回归(LWR)——非参数学习算法,不用担心自变量幂次选择.(因此当二次欠拟合, 三次过拟合的时候不妨尝试这 ...

  5. LCA(Tarjan算法)模板

    一.查询一组的LCA Nearest Common Ancestors A rooted tree is a well-known data structure in computer science ...

  6. shader language学习(1)——shader language简介背景

    shader language,称为着色语言,shade在英语是阴影.颜色深浅的意思.shader language基于物体本身属性和光照条件,计算美格橡塑的颜色值. 实际上这种解释具有明显的时代局限 ...

  7. cobbler-web 网络安装服务器套件 Cobbler(补鞋匠)

    Cobbler作为一个预备工具,使部署RedHat/Centos/Fedora系统更容易,同时也支持Suse和Debian系统的部署. 它提供以下服务集成:   * PXE服务支持 * DHCP服务管 ...

  8. 【第三周】【】cppunit!

    coding.net地址:https://coding.net/u/Boxer_ ssh:git@git.coding.net:Boxer_/homework.git https://coding.n ...

  9. vue+postcss报错: variable '--primary-color' is undefined and used without a fallback

    之前vue-cli3引入postcss的配置: https://www.cnblogs.com/XHappyness/p/7676680.html 发现这么一个问题,我再全局global.css中定义 ...

  10. rem和em学习笔记及CSS预处理

    1.当元素A的字体单位是n rem时,它将根据根元素(html)的font-size的大小作为基准,比如   parent-div中的em-div的font-size为2rem,他的基准就是html的 ...