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 ...
随机推荐
- 622.设计循环队列 javascript实现
设计你的循环队列实现. 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环.它也被称为“环形缓冲器”. 循环队列的一个好处是我们可以利用这个队列 ...
- Redis5.0:现公测全免费,点击就送,注册账号,即开即用
华为云分布式缓存服务Redis,是华为云服务的一款核心产品. 分布式缓存Redis是一款内存数据库服务,基于双机热备的高可用架构,提供单机.主从.集群等丰富类型的缓存类型. 现推出最新版本Redis5 ...
- MySQL 中的数据类型介绍
1.MySQL 数据类型 MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 2.数值类型(12) 2.1. ...
- HTML页面模板代码
作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主.有不正确的地方,欢迎批评指正 HTML页面模板代码 常用的页面模板 & ...
- Python Requests库简单入门
我对Python网络爬虫的学习主要是基于中国慕课网上嵩天老师的讲授,写博客的目的是为了更好触类旁通,并且作为学习笔记之后复习回顾. 1.引言 requests 库是一个简洁且简单的处理HTTP请求的第 ...
- Python:集合操作总结
集合是一组无序排列的不重复元素集 [注]:集合的最大作用是对一个序列进行去重操作 一.集合的分类 在Python中集合分为两类,为可变集合(set)和不可变集合(frozenset).对于可变集合(s ...
- C# 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序。
在菜单 “项目”的最下面 工程属性 菜单,选择“生成”选项卡,将目标平台由“Amy CPU”或者“*64”改成“*86”.
- 团队作业——王者光耀:team
光耀101 <光耀101>是福州大学数计学院计算机专业推出的中国首部程序猿脱发养成节目.由张栋担任发起人,刘晨瑶.畅畅担任导师. 该节目召集了你猜多少位选手,通过任务.训练.考核,让选 ...
- Eclipse的黑色主题背景(github)
MoonRise UI Theme An early version of a dark UI theme for Eclipse 4+. Requirements Eclipse 4.2+ In ...
- BETA阶段冲刺集合
冲刺开始: https://www.cnblogs.com/LZTZ/p/9097296.html 第一天: https://www.cnblogs.com/LZTZ/p/9097303.html 第 ...