平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树

(a)和(b)都是排序二叉树,但是查找(b)的93节点就需要查找6次,查找(a)的93节点就需要查找3次,所以(b)的效率不高。

平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树。它或者是一颗空树,或者是具有下列性质的二叉树:它的左子树和右子树的深度只差的绝对值不超过1。若将二叉树上节点的平衡因子BF(Balance Factor)定义为该节点的左子树的深度减去它右子树的深度,则平衡二叉树上所有节点的平衡因子只可能是-1,0,1。只要二叉树上有一个节点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。

上图(a)是平衡二叉树,(b)不是平衡二叉树,因为有的节点的平衡因子大于1了。

插入节点的大致思路:

  • 首先找到插入节点的位置,插入节点
  • 插入节点后,调整相关节点的平衡因子
  • 调整平衡因子后,如果发现树不平衡了,就要进行节点的调整(单左旋转,或单右旋转,或双旋转(先左后又,或者先右后左)。

avl_tree.h

#ifndef __AVLTREE__
#define __AVLTREE__ #include<stdio.h>
#include<malloc.h>
#include<assert.h>
#include "nodestack.h" #define Type int
#define FALSE 0
#define TRUE 1
#define BOOL int typedef struct AVLNode{
Type data;
struct AVLNode* left;
struct AVLNode* right;
int bf;//平衡因子
}AVLNode; typedef struct AVLTree{
struct AVLNode* root;
}AVLTree; void init_avl_tree(AVLTree* avl);
//插入节点
BOOL insert_avl(AVLTree* avl, Type t); #endif

avl_tree.c

#include "avl_tree.h"

void init_avl_tree(AVLTree* avl){
avl->root = NULL;
}
AVLNode* malNode(Type x){
AVLNode* t = (AVLNode*)malloc(sizeof(AVLNode));
assert(NULL != t);
t->data = x;
t->left = NULL;
t->right = NULL;
t->bf = 0;
return t;
}
//右旋转
void rotateR(AVLNode** t){
AVLNode* subR = *t;
*t = (*t)->left;
subR->left = (*t)->right;
(*t)->right = subR;
(*t)->bf = 0;
subR->bf = 0; }
//左旋转
void rotateL(AVLNode** t){
AVLNode* subL = *t;
*t = (*t)->right;
subL->right = (*t)->left;
(*t)->left = subL;
(*t)->bf = 0;
subL->bf = 0; }
//左右旋转
void rotateLR(AVLNode** t){
AVLNode* subR = *t;
AVLNode* subL = subR->left;
*t = subL->right; subL->right = (*t)->left;
(*t)->left = subL;
if((*t)->bf <= 0){///??
subL->bf = 0;
}
else{
subL->bf = -1;
} subR->left = (*t)->right;
(*t)->right = subR;
if((*t)->bf == -1){
subR->bf = 1;//???
}
else{
subR->bf = 0;//???
} (*t)->bf = 0;
}
//右左旋转
void rotateRL(AVLNode** t){
AVLNode* subL = *t;
AVLNode* subR = subL->right;
*t = subR->left; subR->left = (*t)->right;
(*t)->right = subR;
if((*t)->bf >= 0){
subR->bf = 0;
}
else{
subR->bf = 1;
} subL->right = (*t)->left;
(*t)->left = subL;
if((*t)->bf == 1){
subL->bf = -1;
}
else{
subL->bf = 0;
} (*t)->bf = 0;
}
//插入树的节点
BOOL insert_avl_node(AVLNode** t, Type x){
AVLNode* p = *t;
AVLNode* parent = NULL; nodestack st;
init(&st); while(p != NULL){
if(x == p->data)
return FALSE;
parent = p;
push(&st, parent);
if(x < p->data)
p = p->left;
else
p = p->right;
}
p = malNode(x);
//插入节点为root节点
if(parent == NULL){
*t = p;
return TRUE;
}
//插入节点不是root节点
if(x < parent->data)
parent->left = p;
else
parent->right = p; //调整BF
while(length(&st) != 0){
parent = getTop(&st);
pop(&st);
if(parent->left == p){
parent->bf--;
}
else{
parent->bf++;
} if(parent->bf == 0){
break;
}
if(parent->bf == 1 || parent->bf == -1){
p = parent;
}
else{
//旋转树,让树变成平衡树
int flag = (parent->bf < 0) ? -1 : 1;
//符号相同,说明是一条直线,不是折线,所以单旋转
if(p->bf == flag){
//因为是撇/,所以右旋转
if(flag == -1){
rotateR(&parent);
}
//因为是捺\,所以左旋转
else{
rotateL(&parent);
}
}
//符号不同,说明是折线,所以双旋转
else{
//折线的角指向右>
if(flag == 1){
rotateRL(&parent);
}
//折线的角指向左<
else{
rotateLR(&parent);
}
}
break;
}
} if(length(&st) == 0){
*t = parent;
}
else{
AVLNode* q = getTop(&st);
if(q->data > parent->data){
q->left = parent;
}
else{
q->right = parent;
}
} clear(&st);
return TRUE;
}
//插入节点
BOOL insert_avl(AVLTree* avl, Type t){
return insert_avl_node(&avl->root, t);
}

avl_treemain.c

#include "avl_tree.h"

int main(){
AVLTree avl;
init_avl_tree(&avl); //Type ar[] = {13,24,37,90,53};
//Type ar[] = {30,20,10};
//Type ar[] = {30,20,40,10,25,5,22,28,21};
//Type ar[] = {30,20,10};
//Type ar[] = {50,40,60,10,45,70,5,30,20,12};
Type ar[] = {30,20,50,10,40,70,60,80,55}; int n = sizeof(ar) / sizeof(Type);
for(int i = 0; i < n; ++i){
insert_avl(&avl, ar[i]);
}
return 0;
}

完整代码

编译方法:g++ -g nodestack.c avl_tree.c avl_treemain.c

平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树的更多相关文章

  1. 数据结构与算法——平衡二叉树(AVL树)

    目录 二叉排序树存在的问题 基本介绍 单旋转(左旋转) 树高度计算 旋转 右旋转 双旋转 完整代码 二叉排序树存在的问题 一个数列 {1,2,3,4,5,6},创建一颗二叉排序树(BST) 创建完成的 ...

  2. C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解

    剑指offer 面试题39:判断平衡二叉树 提交网址:  http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...

  3. [CareerCup] 4.1 Balanced Binary Tree 平衡二叉树

    4.1 Implement a function to check if a binary tree is balanced. For the purposes of this question, a ...

  4. 平衡二叉树(Balanced Binary Tree)

    平衡二叉树(Balanced Binary Tree)/AVL树:

  5. [Algorithm] Find Max Items and Max Height of a Completely Balanced Binary Tree

    A balanced binary tree is something that is used very commonly in analysis of computer science algor ...

  6. LeetCode 110. 平衡二叉树(Balanced Binary Tree) 15

    110. 平衡二叉树 110. Balanced Binary Tree 题目描述 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点的左右两个子树 ...

  7. AVL平衡二叉树的各种问题(Balanced Binary Tree)

    AVL树或者是一棵空树,或者是具有以下性质的非空二叉搜索树: 1. 任一结点的左.右子树均为AVL树: 2.根结点左.右子树高度差的绝对值不超过1. 1.声明 #include<iostream ...

  8. [LeetCode] 110. Balanced Binary Tree ☆(二叉树是否平衡)

    Balanced Binary Tree [数据结构和算法]全面剖析树的各类遍历方法 描述 解析 递归分别判断每个节点的左右子树 该题是Easy的原因是该题可以很容易的想到时间复杂度为O(n^2)的方 ...

  9. 110. Balanced Binary Tree - LeetCode

    Question 110. Balanced Binary Tree Solution 题目大意:判断一个二叉树是不是平衡二叉树 思路:定义个boolean来记录每个子节点是否平衡 Java实现: p ...

随机推荐

  1. mysql累积聚合

    累积聚合为聚合从序列内第一个元素到当前元素的数据,如为每个员工返回每月开始到现在累积的订单数量和平均订单数量 行号问题有两个解决方案,分别是为使用子查询和使用连接.子查询的方法通常比较直观,可读性强. ...

  2. Wireshark的基本使用——过滤器

    前言 网络上关于Wireshark的教程已有不少,博主就简单介绍一下Wireshark分析数据包时最重要的技巧之一的过滤器..一次性嗅探到的数据包有很多,想要高效地提取出你想要的数据包或者对某个数据包 ...

  3. iOS SQLite详解

    这周比较忙,前几天都加班到11点左右,基本都是到家都是12点左右(稍稍的抱怨一下,免费加班,何为免费,就是任何补偿都没有,例如调休,加班薪,餐补等各项福利,是一点都没有呀)因为App要上线了!App上 ...

  4. 更新计算机名称后TFS文件无法迁出

    本人最新刚刚最新了一下计算机名称,但在迁出TFS文件时报如下错误: 如果最近已重命名此计算机,则可通过运行“tf workspaces /updateComputerName:oldComputerN ...

  5. 《C#并发编程经典实例》学习笔记—异步编程关键字 Async和Await

    C# 5.0 推出async和await,最早是.NET Framework 4.5引入,可以在Visual Studio 2012使用.在此之前的异步编程实现难度较高,async使异步编程的实现变得 ...

  6. 第一册:lesson sixty one.

    原文: A bad cold. A:Where is Jim? B:He is in bed. A:What's the matter with him? B:He fells ill. A:He l ...

  7. 结构型---装饰者模式(Decorator Pattern)

    定义 装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能. Component抽象构件           Component是一个接口或者是抽象 ...

  8. SpringMVC 与 REST.

    一.REST 的基础知识 我敢打赌这并不是你第一次听到或读到REST这个词.当讨论REST时,有一种常见的错误就是将其视为“基于URL的Web服务”—— 将REST作为另一种类型的RPC机制,只不过是 ...

  9. java并发编程小结

    旭日Follow_24 的CSDN 博客 ,全文地址请点击: https://blog.csdn.net/xuri24/article/details/82078467 线程简介: 线程是操作系统调度 ...

  10. Excel通用类工具(二)

    前言 上一篇中写到了用反射来处理类中的不用的属性,但是Excel的列名还得手动输入,这样还是比较麻烦的,今天这篇就利用自定义注解来解决手动传入列名的问题:其实很简单的,只需要在上一篇的基础上加一个类就 ...