AVL树 - 学习笔记
2017-08-29 14:35:55
writer:pprp
AVL树就是带有平衡条件的二叉查找树。每个节点的左子树和右子树高度相差最多为1的二叉查找树
空树的高度定为-1
对树的修正称为旋转
对内部的来说是双旋,对外部的调整修正是单旋

----------------------------------------------------------------------------------------------------------------

由于一次旋转总能解决问题,因此编写非递归程序要比编写递归程序快很多,但是非递归方式编写比较难
还是很多人都选择递归的方式,这里也选择递归的方式,比较容易理解;
代码如下:(还没有完全写好,删除部分不太理解)
/*
@theme:AVL tree
@writer:pprp
@begin:14:32
@end:16:26
@declare:带有平衡条件的二叉查找树,这里不需要一个创建节点的函数,
因为相关操作已经在Insert函数中完成了
@date:2017/8/29
*/ #include <bits/stdc++.h> using namespace std;
struct AvlNode;
typedef struct AvlNode* Position;
typedef struct AvlNode* AvlTree; AvlTree MakeEmpty(AvlTree T);
Position Find(int X, AvlTree T);
Position FindMin(AvlTree T);
Position FindMax(AvlTree T);
AvlTree Insert(int X, AvlTree T);
AvlTree Delete(int X, AvlTree T); static Position SingleRotateWithLeft(Position);
static Position DoubleRotateWithLeft(Position);
static Position SingleRotateWithRight(Position);
static Position DoubleRotateWithRight(Position); //AVL tree节点声明
struct AvlNode
{
int element;
AvlTree left;
AvlTree right;
int Height;
}; //一个快速的函数来返回节点高度
static int Height(Position P)
{
if(P == NULL)
return -;
else
return P->Height;
} //向AVL树中插入节点的函数
AvlTree Insert(int X, AvlTree T)
{
//如果节点为空,建立然后返回一个单节点的树
if(T == NULL)
{
T = new AvlNode();
//如果失败
if(T == NULL)
{
cout << "Out of place!" << endl;
}
else
{
T->element = X;
T->Height = ;
T->left = T->right = NULL;
}
}
else if(X < T->element) //如果头结点不为空
{
T->left = Insert(X,T->left);
//question
//如果不满足AVL tree的要求了,且左侧高于右侧,对左侧进行处理
if(Height(T->left) - Height(T->right) == )
{
if(X < T->left->element)//如果小于左边
T = SingleRotateWithLeft(T);//进行左侧的单旋
else
T = DoubleRotateWithLeft(T);//进行左侧的双旋
}
}
else if(X > T->element)
{
T->right = Insert(X, T->right);
//如果右侧高于左侧进行旋转
if(Height(T->right) - Height(T->left) == )
{
if(X > T->right->element)
T = SingleRotateWithRight(T);
else
T = DoubleRotateWithRight(T);
}
}
//else X is in the tree already , we'll do nothing
T->Height = max(Height(T->left),Height(T->right)) + ;
return T;
} //执行单旋转的左边 LL
static Position SingleRotateWithLeft(Position K2)
{
Position K1;
K1 = K2->left;
K2->left = K1->right;
K1->right = K2; K2->Height = max(Height(K2->left),Height(K2->right))+;
K1->Height = max(Height(K1->left),Height(K1->right))+; return K1;
} //执行双旋转的左边 LR
static Position DoubleRotateWithLeft(Position K3)
{
//rotate between K1 and K2
K3->left = SingleRotateWithRight(K3->left);
//rotate between K3 and K2
return SingleRotateWithLeft(K3);
} //执行单旋转的右边 RR
static Position SingleRotateWithRight(Position K1)
{
Position K2; K2 = K1->left;
K1->left = K2->right;
K2->right = K1; K1->Height = max(Height(K1->right),Height(K2->left))+;
K2->Height = max(Height(K2->right),Height(K2->left))+; return K2;
}
//执行双旋转的右边 RL
static Position DoubleRotateWithRight(Position K3)
{
K3->right = SingleRotateWithLeft(K3->right);
return SingleRotateWithRight(K3);
} //进行中序遍历
void MidPrint(AvlTree T)
{
if(T != NULL)
{
MidPrint(T->left);
cout << T->element << " ";
MidPrint(T->right);
}
} //查找函数,返回一个指针
Position Find(int X, AvlTree T)
{
if(T == NULL)
return NULL;
if(X < T->element)
return Find(X, T->right);
else if(X > T->element)
return Find(X, T->left);
else
return T;
} //找到最大值
Position FindMax(AvlTree T)
{
if(T == NULL)
return NULL;
else if(T->right == NULL)
return T;
else
return FindMax(T->right);
} //找到最小值
Position FindMin(AvlTree T)
{
if(T == NULL)
return NULL;
else if(T->left == NULL)
return T;
else
return FindMin(T->left);
} //删除节点,返回根节点
AvlTree Delete(int X, AvlTree T)
{
AvlTree tmp = Find(X,T);
if(T == NULL || tmp == NULL)
return NULL;
if(X < T->element)//如果在左子树中
{
T->left = Delete(X,T->left);
//开始调整由于删除带来的影响
if(Height(T->right) - Height(T->left) == )
{
AvlTree K = T->right;//因为右边高度比较高
if(Height(K->left) > Height(K->right))
DoubleRotateWithRight(T);
else
SingleRotateWithRight(T);
}
}
else if(X > T->element) //如果在右子树中
{
T->right = Delete(X,T->right);
if(Height(T->left) - Height(T->right) == )
{
AvlTree K = T->left;
if(Height(K->right) > Height(K->left))
DoubleRotateWithLeft(T);
else
SingleRotateWithLeft(T);
}
}
else if(X == T->element)
{
// 如果两个孩子非空
if(T->left && T->right)
{
//维护AVL树特性:本来可以选择两种方式进行删除
//现在要优先删除高度比较高的子树
if(Height(T->left) > Height(T->right))
{
AvlTree Max = FindMax(T->left); //找到最大值
T->element = Max->element; //将内容进行替换
delete(Max); //删除该节点
Max = NULL;
}
else
{
AvlTree Min = FindMin(T->right);
T->element = Min->element;
delete(Min);//删除该节点
Min = NULL;
}
}
else //如果有一个子节点或者没有子节点
{
AvlTree tmp = T;
T = T->left == NULL ? T->right:T->left;
delete(tmp);
}
}
return T;
} //清空整个树
AvlTree MakeEmpty(AvlTree T)
{
if(T!= NULL)
{
MakeEmpty(T->right);
MakeEmpty(T->left);
delete(T);
}
} int main()
{ AvlTree T;
int n, tmp;
cin >> n;
for(int i = ; i < n ; i++)
{
cin >> tmp;
T = Insert(tmp,T);
} return ;
}
AVL树 - 学习笔记的更多相关文章
- zkw线段树学习笔记
zkw线段树学习笔记 今天模拟赛线段树被卡常了,由于我自带常数 \(buff\),所以学了下zkw线段树. 平常的线段树无论是修改还是查询,都是从根开始递归找到区间的,而zkw线段树直接从叶子结点开始 ...
- 仙人掌&圆方树学习笔记
仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...
- 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解
什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...
- Treap-平衡树学习笔记
平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...
- JSOI2008 Blue Mary开公司 | 李超线段树学习笔记
题目链接:戳我 这相当于是一个李超线段树的模板qwqwq,题解就不多说了. 代码如下: #include<iostream> #include<cstdio> #include ...
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- CART分类与回归树 学习笔记
CART:Classification and regression tree,分类与回归树.(是二叉树) CART是决策树的一种,主要由特征选择,树的生成和剪枝三部分组成.它主要用来处理分类和回归问 ...
- B和B+树学习笔记
二叉树 如果数据都在内存中,我们就用平衡二叉查找树即可,这样效率最高. 在前面的文章中我使用过红黑树(大致平衡的二叉查找树),500万节点时,搜索的深度可以达到50,也就是需要50次指针操作才能获取到 ...
- Trie树 字典树-学习笔记
字符串--蒟蒻永远的阴影 对于字符串匹配 KMP很好的解决了以一个文本串匹配一个模板串的问题 但如果模板串有多个呢 这是KMP不再适用 我们引入一个新的数据结构--字典树 (当然又有像AC自动机这样更 ...
随机推荐
- [报错]Fast enumeration variables cannot be modified in ARC by default; declare the variable __strong to allow this
今天写了下面的快速枚举for循环代码,从按钮数组subButtons中取出button,然后修改button的样式,在添加到view中 for (UIButton *button in subButt ...
- 基于spring的quartz定时框架,实现简单的定时任务功能
在项目中,经常会用到定时任务,这就需要使用quartz框架去进行操作. 今天就把我最近做的个人主页项目里面的定时刷新功能分享一下,很简单. 首先需要配置一个配置文件,因为我是基于spring框架的,所 ...
- python学习笔记(二)— 列表(list)
列表也叫数组,列表定义,使用[]即可:列表里面可以再套列表,一个里面套一个列表,叫二维数组:一个里面套一个列表,里面的列表再套一个列表,这个叫三维数组,套几层就是几维,定义格式如下: list1 = ...
- 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...
- 使用paramiko的SFTP get或put整个目录
在<使用paramiko执行远程linux主机命令>中举例说明了执行远程linux主机命令的方法,其实paramiko还支持SFTP传输文件. 由于get或put方法每次只能传输一个文件, ...
- Matlab GUI memo
有一段时间没写博客,一周4篇文章都坚持不下来,不知道写哪个方面的内容,写研究相关就怕论文查重查到,其他方面也没太多时间去学.还是花时间多学点其他方面.废话到此,很早就做过matlab gui相关,现在 ...
- win下如何解决在chrome的同源访问问题
引子:本来是想验证如果在网页中包含多个框架,那么就会存在两个以上的不同全局环境,如果从一个框架引用另一个框架的数据比如数组a,那么用 instanceof 判断这个数组a是不是另个框架Array的实例 ...
- NOSQL概念入门
一.NOSQL概念 随着大数据时代的到来,分布式存储得到了快速发展,其中比较受欢迎的,主要以key-value键值对存储的非关系型数据库进入了大家的视野. NOSQL的全称是Not Only Sql, ...
- PKU 4334 Trouble(哈希)
原题链接 思路:哈希存入相反数 注意:HDU不支持long long要使用__int64 #include<cstdio> #include<cstring> #define ...
- 软工网络15团队作业1——团队组队&展示
一.团队展示 1.队名:想不出队名 2.队员学号(标记组长) 201521123064 郭炜埕 201521123066 郑晓丽 201521123067 廖怡洁 201521123068 包梦榕 2 ...