04-树4. Root of AVL Tree-平衡查找树AVL树的实现
对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是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树的实现的更多相关文章
- 【PAT甲级】1066 Root of AVL Tree (25 分)(AVL树建树模板)
题意: 输入一个正整数N(<=20),接着输入N个结点的值,依次插入一颗AVL树,输出最终根结点的值. AAAAAccepted code: #define HAVE_STRUCT_TIMESP ...
- 详解平衡二叉树(AVL tree)平衡操作(图+代码)
* 左左就右旋,右右就左旋 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int max ...
- PAT甲级1066. Root of AVL Tree
PAT甲级1066. Root of AVL Tree 题意: 构造AVL树,返回root点val. 思路: 了解AVL树的基本性质. AVL树 ac代码: C++ // pat1066.cpp : ...
- 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 ...
- 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 ...
- PAT甲级1123. Is It a Complete AVL Tree
PAT甲级1123. Is It a Complete AVL Tree 题意: 在AVL树中,任何节点的两个子树的高度最多有一个;如果在任何时候它们不同于一个,则重新平衡来恢复此属性.图1-4说明了 ...
- HDU 2193 AVL Tree
AVL Tree An AVL tree is a kind of balanced binary search tree. Named after their inventors, Adelson- ...
- 数据结构和算法(Golang实现)(28)查找算法-AVL树
AVL树 二叉查找树的树高度影响了查找的效率,需要尽量减小树的高度,AVL树正是这样的树. 一.AVL树介绍 AVL树是一棵严格自平衡的二叉查找树,1962年,发明者Adelson-Velsky和La ...
- 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树
某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...
- 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 ...
随机推荐
- Redis5.0:在这些场景使用,高效率还低成本!
很多大型电商网站.视频直播和游戏应用等,存在大规模数据访问,对数据查询效率要求高,且数据结构简单,不涉及太多关联查询. 这种场景使用Redis,在速度上对传统磁盘数据库有很大优势,能够有效减少数据库磁 ...
- 【ANSIBLE】ansible控制windows插件安装及运行error与解决方法
一. 问:因pip版本问题无法安装kerberos 答:安装提示需要先安装pip升级包 下载pip9.0.1升级包: https://pypi.python.org/packages/b6/ac/70 ...
- AOP:静态代理实现方式①通过继承②通过接口
文件结构: 添加日志: package com.wangcf.manager; public class LogManager { public void add(){ System.out.prin ...
- 查看dll依赖项
win7 系统: 开始-->所有程序->vs2012文件夹->vs tools->对应的命令提示符 输入命令: dumpbin /dependents 你的文件(可以是exe, ...
- struts2 不返回result的做法
有时候 比如提交一个弹框的表单 提交成功后我们只是让表单关闭并不进行页面跳转,那么action 里面就returne null, 然后result 也不用配置了 版权声明:本文为博主原创文章,未经博主 ...
- lintcode-451-两两交换链表中的节点
451-两两交换链表中的节点 给一个链表,两两交换其中的节点,然后返回交换后的链表. 样例 给出 1->2->3->4, 你应该返回的链表是 2->1->4->3. ...
- 【第九周】psp
代码累计 300+575+475+353+620=2223 随笔字数 1700+3000+3785+4210+4333=17695 知识点 java反射机制 数据库技术 动态规划算法 pyth ...
- CentOS7 修改分辨率
1. 修改文件: vi /boot/grub2/grub.cfg 2. 在linux16 开头的哪一行 增加 vga=0x341 修改为1024x768 3. 重启..
- C#开发移动应用 - 环境搭建
前言 其实从2013开始就想用Xamarin,奈何 当初收费一座大山压在身上 完全无法见得庐山真面目 后面2015,微软收购Xamarin,没过多久就宣布对个人用户免费..那个兴奋劲就别提了.. 兴奋 ...
- adb命令模拟按键事件KeyCode
例子: //这条命令相当于按了设备的Backkey键 adb shell input keyevent 4 //可以解锁屏幕 adb shell input keyevent 82 //在屏幕上做划 ...