对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是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. python程序设计——面向对象程序设计:属性

    python 3.x 的属性 可以将属性设置为 可读,可修改,可删除 # 只读属性,不允许修改和删除 class Test: def __init__(self,value): self.__valu ...

  2. centos7挂载Windows共享文件夹(学习笔记)

    centos7挂载windows共享文件夹 练习环境:centos7是安装在台式机的虚拟机,Windows共享文件夹是公司服务器的共享文件夹(已设置好的共享) 步骤 1. 设置挂载点:mkdir /m ...

  3. [寒假学习笔记](一)Markdown语法学习

    Markdown 学习 在博客园上使用markdown编辑,记录学习进度,以来日可以复习 前期准备 1. 安装markdownpad2 官网直接找下载安装,遇到bug他会自动提示信息,跟着提示去安装一 ...

  4. Python爬虫入门(3-4):Urllib库的高级用法

    1.分分钟扒一个网页下来 怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器解释才呈现出来的,实质它 是一段HTML代码,加 JS.CS ...

  5. 软件工程 speedsnail 第二次冲刺10

    20150527 完成任务:蜗牛碰到线后速度方向的调整:已经基本实现多方向的反射: 遇到问题: 问题1 反射角的问题 解决1 利用tan()三角函数 明日任务: 大总结.找到新问题.布置下一次冲刺方案

  6. linux +redis 安装 +mongo 安装

    Linux 下redis安装 本教程使用的最新文档版本为 2.8.17,下载并安装: $ wget http://download.redis.io/releases/redis-2.8.17.tar ...

  7. 《我是IT小小鸟》读笔

    兴趣是第一原则.一定要根据自己的兴趣确定发展方向,不要盲目从众和跟风.没有一个人的经历是可以复制的,多思考,不要照搬他人的做法,学习一下想法还是可以的,具体方法因人而异.学习软件技术时,不仅在知识节点 ...

  8. 第11章 认识和学习bash

    认识bash这个shell 硬件.内核和shell 用户操作计算机流程如下: 用户——>用户界面(shell,KDE,application)——>核心(kernel)——>硬件(h ...

  9. PXE Centos7和Centos6

    外网网卡:192.168.23.10, 内网网卡:192.168.10.2 PXE(preboot execute environment,预引导执行环境)是由Intel公司开发的最新技术,工作于Cl ...

  10. yum 安装php环境

    centos下安装php环境 | 浏览:3831 | 更新:2014-11-04 17:01 1 2 3 分步阅读 在网上看了很多,很多都不能用,所以就把能用的实践下,过程记录下,方便自己和网友以后查 ...