第一步:定义结构体

typedef struct Node{
int d; //data
int h=; //height
struct Node* l=NULL;
struct Node* r=NULL;
Node(int d=):d(d){
}
}Node;

这个结构体和常规的二叉树结构体很相似。但是不同的是多了个属性“h”(height)。用这个属性来记录结点的高度,叶子结点为1,空结点为0 。

第二部:编写BST树的插入函数

Node* insert(Node* p,int v){
Node * node=new Node(v);
if(!p){
return node;
}
if(v < p->d){ //左子树
if(p->l){
p->l=insert(p->l,v);
}else{
p->l=node;
}
}else{
if(p->r){
p->r=insert(p->r,v);
}else{
p->r=node;
}
}
// setHeight(p);
//平衡旋转代码 //end of 平衡旋转代码
return p;
}

第三步:编写高度获取与设置的辅助函数

高度获取:

int getHeight(Node* node){
if(node) return node->h; //如果非空返回这个结点的height
return ; //空节点的高度是0
}

高度设置:

void setHeight(Node* node){    //取左右子树高度的最大值,记得+1
node->h=max(getHeight(node->l),getHeight(node->r))+;
}

第四步:编写平衡旋转函数

当左右子树的height相差为2时,就要调用平衡旋转函数进行旋转。一共有4种旋转模式:

(注:一下图片采用自博客:http://www.cnblogs.com/Camilo/p/3917041.html,如果侵权请联系我删除)

左子树左结点引起的不平衡:

Node* LL(Node* node){
Node* re=node->l;
node->l=re->r;
re->r=node;
setHeight(node); //注意:先进行这一步。因为node是re的子结点,从下往上调整
setHeight(re);
return re;
}

右子树右结点引起的不平衡:

Node* RR(Node* node){
Node* re=node->r;
node->r=re->l;
re->l=node;
setHeight(node);
setHeight(re);
return re;
}

(注:编写技巧是在LL函数的基础上,把所有的r写成l,把所有的l写成r,轮换对称思想)

左子树右结点引起的不平衡:

Node* LR(Node* node){
node->l=RR(node->l);
node=LL(node);
return node;
}

右子树左结点引起的不平衡:

Node* RL(Node* node){
node->r=LL(node->r);
node=RR(node);
return node;
}

第五步:在BST树的插入函数中编写平衡旋转代码:

Node* insert(Node* p,int v){
Node * node=new Node(v);
if(!p){
return node;
}
if(v < p->d){ //左子树
if(p->l){
p->l=insert(p->l,v);
}else{
p->l=node;
}
}else{
if(p->r){
p->r=insert(p->r,v);
}else{
p->r=node;
}
}
setHeight(p);
//平衡旋转代码
if(getHeight(p->l)-getHeight(p->r)==){ //左子树不平衡
if(getHeight(p->l->l)>getHeight(p->l->r)){//左结点不平衡
p=LL(p);
}else{ //右结点不平衡
p=LR(p);
}
}
if(getHeight(p->r)-getHeight(p->l)==){ //右子树不平衡
if(getHeight(p->r->l)>getHeight(p->r->r)){//左结点不平衡
p=RL(p);
}else{ //右结点不平衡
p=RR(p);
}
}
//end of 平衡旋转代码
return p;
}

打个OJ测试一下:1123. Is It a Complete AVL Tree

AC代码:

#include <stdio.h>
#include <queue>
#include <algorithm> using namespace std; typedef struct Node{
int d; //data
int h=; //height
struct Node* l=NULL;
struct Node* r=NULL;
Node(int d=):d(d){
}
}Node; int getHeight(Node* node){
if(node) return node->h; //如果非空返回这个结点的height
return ; //空节点的高度是0
} void setHeight(Node* node){ //取左右子树高度的最大值,记得+1
node->h=max(getHeight(node->l),getHeight(node->r))+;
} Node* LL(Node* node){
Node* re=node->l;
node->l=re->r;
re->r=node;
setHeight(node); //注意:先进行这一步。因为node是re的子结点,从下往上调整
setHeight(re);
return re;
} Node* RR(Node* node){
Node* re=node->r;
node->r=re->l;
re->l=node;
setHeight(node);
setHeight(re);
return re;
} Node* LR(Node* node){
node->l=RR(node->l);
node=LL(node);
return node;
} Node* RL(Node* node){
node->r=LL(node->r);
node=RR(node);
return node;
} Node* insert(Node* p,int v){
Node * node=new Node(v);
if(!p){
return node;
}
if(v < p->d){ //左子树
if(p->l){
p->l=insert(p->l,v);
}else{
p->l=node;
}
}else{
if(p->r){
p->r=insert(p->r,v);
}else{
p->r=node;
}
}
setHeight(p);
//平衡旋转代码
if(getHeight(p->l)-getHeight(p->r)==){ //左子树不平衡
if(getHeight(p->l->l)>getHeight(p->l->r)){//左结点不平衡
p=LL(p);
}else{ //右结点不平衡
p=LR(p);
}
}
if(getHeight(p->r)-getHeight(p->l)==){ //右子树不平衡
if(getHeight(p->r->l)>getHeight(p->r->r)){//左结点不平衡
p=RL(p);
}else{ //右结点不平衡
p=RR(p);
}
}
//end of 平衡旋转代码
return p;
} int cnt=; int main(){
// freopen("I:\\pat\\树\\AVL\\1123_2.txt","r",stdin);
int n,t;
scanf("%d",&n);
Node * root;
for(int i=;i<n;i++){
scanf("%d",&t);
root=insert(root,t);
}
queue<Node*> q;
q.push(root);
bool findNull=;
bool yes=;
bool after=;
while(!q.empty()){
Node* t=q.front();
q.pop();
printf("%d",t->d);
cnt++;
if(cnt!=n)
printf(" ");
if(t->l){
q.push(t->l);
if(after) yes=;
}
else after=;
if(t->r){
q.push(t->r);
if(after) yes=;
}
else after=;
}
puts("");
puts(yes?"YES":"NO");
return ;
}

一步一步编写AVL树的更多相关文章

  1. 一步一步写平衡二叉树(AVL树)

    平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树.1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵 ...

  2. AVL树的插入与删除

    AVL 树要在插入和删除结点后保持平衡,旋转操作必不可少.关键是理解什么时候应该左旋.右旋和双旋.在Youtube上看到一位老师的视频对这个概念讲解得非常清楚,再结合算法书和网络的博文,记录如下. 1 ...

  3. 一步一步教你编写与搭建自动化测试框架——python篇

    [本文出自天外归云的博客园] 这两天用python写了一个自动化测试框架,取名为Auty.准备用来做Web方面的接口测试,以下为Auty框架一步一步的搭建过程——

  4. 一步一步理解线段树——转载自JustDoIT

    一步一步理解线段树   目录 一.概述 二.从一个例子理解线段树 创建线段树 线段树区间查询 单节点更新 区间更新 三.线段树实战 -------------------------- 一 概述 线段 ...

  5. 算法与数据结构(十一) 平衡二叉树(AVL树)

    今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...

  6. AVL树的平衡算法(JAVA实现)

      1.概念: AVL树本质上还是一个二叉搜索树,不过比二叉搜索树多了一个平衡条件:每个节点的左右子树的高度差不大于1. 二叉树的应用是为了弥补链表的查询效率问题,但是极端情况下,二叉搜索树会无限接近 ...

  7. 【数据结构】平衡二叉树—AVL树

    (百度百科)在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增 ...

  8. 我的新发现:AVL树旋转的一个特性

    关于AVL树旋转的代码网络上铺天盖地. 一些经典的实现方法如下: AVLTree SingleLeftRotation(AVLTree A) { AVLTree B = A->left; A-& ...

  9. 纸上谈兵:AVL树

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 二叉搜索树的深度与搜索效率 我们在树, 二叉树, 二叉搜索树中提到,一个有n个节点 ...

随机推荐

  1. SpringBoot 系列教程自动配置选择生效

    191214-SpringBoot 系列教程自动配置选择生效 写了这么久的 Spring 系列博文,发现了一个问题,之前所有的文章都是围绕的让一个东西生效:那么有没有反其道而行之的呢? 我们知道可以通 ...

  2. MySQL主键与索引的区别和联系

    MySQL主键与索引的区别和联系   关系数据库依赖于主键,它是数据库物理模式的基石.主键在物理层面上只有两个用途: 惟一地标识一行. 作为一个可以被外键有效引用的对象. 索引是一种特殊的文件(Inn ...

  3. golang语言特性

    1. 垃圾回收 a. 内存⾃动回收,再也不需要开发⼈员管理内存 b. 开发人员专注业务实现,降低了心智负担 c. 只需要new分配内存,不需要释放   2. 天然并发 a. 从语⾔层面⽀持并发,⾮常简 ...

  4. 前端性能优化--回流(reflow)和重绘(repaint)

    HTML加载时发生了什么 在页面加载时,浏览器把获取到的HTML代码解析成1个DOM树,DOM树里包含了所有HTML标签,包括display:none隐藏,还有用JS动态添加的元素等. 浏览器把所有样 ...

  5. swagger2 导出离线Word/PDF/HTML文档

    swagger2离线导出Word/PDF/HTML文档 1.前言 通过前面的两篇博客 我们已经介绍了如何使用spring boot整合swagger2 生成在线的API文档. 但是某些情况下,我们需要 ...

  6. nginx产生【413 request entity too large】错误的原因与解决方法

    项目上在做上传文件(清单导入)的时候产生了这个错误: 从字面上看,说的是请求的实体太大的问题,那么可以联想到是HTTP请求中的Body大小被限制了的原因. Nginx中的[client_max_bod ...

  7. lua中,两种json和table互转方法的效率比较

    lua中json和table的互转,是我们在平时开发过程中经常用到的.比如: 在用lua编写的服务器中,如果客户端发送json格式的数据,那么在lua处理业务逻辑的时候,必然需要转换成lua自己的数据 ...

  8. 2019-11-29-dotnet-通过-WMI-获取指定进程的输入命令行

    原文:2019-11-29-dotnet-通过-WMI-获取指定进程的输入命令行 title author date CreateTime categories dotnet 通过 WMI 获取指定进 ...

  9. .Net IOC框架入门之——Unity

    一.概述 IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection). 作用:将各层的对象以松耦合的方式组织在一 ...

  10. 浅析负载均衡的6种算法,Ngnix的5种算法

    常见的几种负载均衡算法 1.轮询法 将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载. 2.随机法 通过系统的随机算法,根据后端服务器的 ...