AVL树简介

AVL树实际上一个引入了平衡因子的二叉搜索树,该平衡因子保证了每个节点的左右子树高度之差的绝对值不超过1,这样就可以降低树的高度,减少平均搜索长度。

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
1.它的左右子树都是AVL树
2.左右子树高度之差(平衡因子)的绝对值不超过1(-1/0/1)

如果一棵二叉搜索树是高度平衡的,他就是AVL树,如果它有n个结点,那么它的高度就是log2n,搜索时间复杂度O(log2n).

AVL树的插入

1.按照二叉搜索树的方式插入新节点
2.调整节点的平衡因子

pCur插入后,pParent的平衡因子需要调整,插入之前,pParent的平衡因子分为三种情况-1 0 1
1.如果pCur插入到pParent的左侧,只需要给pParent的平衡因子-1
2.如果pCur插入到pParent的右侧,只需要给pParent的平衡因子+1

插入后的平衡因子会有下面三种情况 0 正负1 正负2
1.如果平衡因子为0,说明插入前平衡因子为正负1,插入后满足性质
2.如果平衡因子为正负,说明插入前平衡因子为0,插入后以pParent为根的高度增加,需要继续向上更新
3.如果平衡因子为正负2,违反了AVL树的性质,需要进行旋转处理

AVL树的旋转

当插入节点后造成了不平衡也就是平衡因子为正负2,此时就需要进行旋转。
旋转分为4种情况:

1.新节点插入较高左子树的左侧 --左左:右单旋

2.新节点插入较高右子树的右侧 --右右:左单旋
参考第一种情况

3.新节点插入较高左子树的右侧 --左右:先左单旋再右单旋

4.新节点插入较高右子树的左侧 --右左:先右单旋再左单旋
参考第三种情况图形

AVL树的验证

1.验证为二叉搜索树
看中序遍历可以得到一个有序的序列,就说明为二叉搜索树
2.验证为平衡树
(1)每个节点子树高度差的绝对值不超过1(这是没有引入平衡因子)
(2)节点的平衡因子是否正确

AVL树代码

AVLTree.h

#pragma once#include<iostream>
#include<assert.h>
#include<algorithm>
#include<time.h>using namespace std;template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf;  // balance factorAVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}
};template<class K, class V>
struct AVLTree
{typedef AVLTreeNode<K, V> Node;
public:bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;// 控制平衡// 1、更新平衡因子while (parent){if (cur == parent->_right){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0){break;}else if (abs(parent->_bf) == 1){parent = parent->_parent;cur = cur->_parent;}else if (abs(parent->_bf) == 2){// 说明parent所在子树已经不平衡了,需要旋转处理if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}else if ((parent->_bf == -2 && cur->_bf == -1)){RotateR(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else{assert(false);}break;}else{assert(false);}}return true;}void InOrder(){_InOrder(_root);cout << endl;}bool IsBalance(){return _IsBalance(_root);}
private:bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHT = Height(root->_left);int rightHT = Height(root->_right);int diff = rightHT - leftHT;if (diff != root->_bf){cout << root->_kv.first << "平衡因子异常" << endl;return false;}return abs(diff) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}int Height(Node* root){if (root == nullptr)return 0;return max(Height(root->_left), Height(root->_right)) + 1;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}subR->_bf = parent->_bf = 0;}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}subL->_bf = parent->_bf = 0;}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);subLR->_bf = 0;if (bf == 1){parent->_bf = 0;subL->_bf = -1;}else if (bf == -1){// 错的/*parent->_bf = 0;subL->_bf = 1;*/parent->_bf = 1;subL->_bf = 0;}else if (bf == 0){parent->_bf = 0;subL->_bf = 0;}else{assert(false);}}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;parent->_bf = 0;}else if (bf == 0){parent->_bf = 0;subR->_bf = 0;}else{assert(false);}}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}
private:Node* _root = nullptr;
};

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1#include"AVLTree.h"void TestAVLTree1()
{int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };  // 测试双旋平衡因子调节//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };AVLTree<int, int> t1;for (auto e : a){t1.Insert(make_pair(e, e));}t1.InOrder();cout << "IsBalance:" << t1.IsBalance() << endl;}//验证AVLTree
void TestAVLTree2()
{size_t N = 10000;srand(time(0));AVLTree<int, int> t1;for (size_t i = 0; i < N; ++i){int x = rand();t1.Insert(make_pair(x, i));/* bool ret = t1.IsBalance();if (ret == false){int u = 1;}else{cout << "Insert:" << x << " IsBalance:" <<ret<< endl;}*/}cout << "IsBalance:" << t1.IsBalance() << endl;
}int main()
{//TestAVLTree1();TestAVLTree2();return 0;
}

这就是AVL树的一些介绍,但并没有写上AVL树的删除是因为AVL树删除一个结点将要更新平衡因子到根节点,效率不高,不常见。

AVL树是一棵绝对平衡的二叉搜索树,它的每个结点的左右子树高度差的绝对值都不超过1,这就保证了它的时间复杂度时log(N)。
但是对AVL树的结构修改效率不高,因为要保证平衡而进行旋转。

AVL树(平衡二叉搜索树)详解及C++代码实现相关推荐

  1. 二叉搜索树详解--实现插入和删除

    目录 BST树概念 BST树操作 BST树的查找 BST树的插入 BST树的删除 实现一个自己的BST树 BSTNode类和BSTree类 查找操作; 插入操作: 删除操作: 应用: 二叉搜索树性能分 ...

  2. java二叉搜索树详解

    文章目录 一.概念 二.相关操作 2.0节点相关代码: 2.1查找 2.2插入 2.3删除(重难点) 2.4测试用例 三.小结 提示:以下是本篇文章正文内容,下面案例可供参考 一.概念 二叉搜索树又称 ...

  3. 《恋上数据结构第1季》平衡二叉搜索树、AVL树

    AVL树 二叉搜索树缺点分析 改进二叉搜索树 平衡(Balance) 理想平衡 如何改进二叉搜索树? 平衡二叉搜索树(Balanced Binary Search Tree) AVL树 BST 对比 ...

  4. 五.树,二叉树,二叉搜索树(BST)和自平衡二叉搜索树(AVL)

    1.树 树是一种数据结构 比如:目录结构 树是一种可以递归定义的数据结构 树是由n个节点组成的集合: 如果 n=0, 那这是一颗空树 如果 n>0, 那存在1个节点作为树的根节点,其他节点可以分 ...

  5. 看动画学算法之:平衡二叉搜索树AVL Tree

    简介 平衡二叉搜索树是一种特殊的二叉搜索树.为什么会有平衡二叉搜索树呢? 考虑一下二叉搜索树的特殊情况,如果一个二叉搜索树所有的节点都是右节点,那么这个二叉搜索树将会退化成为链表.从而导致搜索的时间复 ...

  6. 数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

    在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉 ...

  7. 二叉堆详解实现优先级队列

    二叉堆详解实现优先级队列 文章目录 二叉堆详解实现优先级队列 一.二叉堆概览 二.优先级队列概览 三.实现 swim 和 sink 四.实现 delMax 和 insert 五.最后总结 二叉堆(Bi ...

  8. 数据结构与算法-平衡二叉搜索树

    平衡二叉搜索树 1.自平衡的二叉搜索树 2.平衡 (1)空树平衡 (2)非空树平衡 左右子树平衡 左右子树高度差绝对值 <= 1 3.平衡因子 左右子树的高度差的衡量值 -1 0 1 (一)平衡 ...

  9. VC++2012编程演练数据结构《9》平衡二叉搜索树

    平衡二叉搜索树 任何结点的左子树和右子树高度最多相差1的二叉搜索树. (1)AVL树的插入算法 a. 插入结点之后仍然是AVL树,则不调整: b. 插入结点之后不再满足AVL树条件,则进行调整,根据导 ...

  10. 【二叉树进阶】红黑树(Red Black Tree) - 平衡二叉搜索树

    文章目录 一.红黑树的概念 二.红黑树的性质 2.1 红黑树和AVL树效率对比 三.红黑树的结构(KV模型) 四.红黑树的插入 4.1 插入节点 4.2 平衡化操作(难点) 4.2.1 情况一 4.2 ...

最新文章

  1. 树莓派4装Ubuntu
  2. 【C语言】复合逻辑运算
  3. mysql 中文乱码 或 问号
  4. 计算机组装与维修单招,单招职二 计算机组装与维修试卷.doc
  5. 报错The sandbox is not in sync with the Podfile.lock
  6. leetcode33 --- search
  7. eclipse 使用 maven 无法编译 jsp 文件的问题
  8. PC服务器实现海量数据存取的方法
  9. 读掘金小册组件精讲总结3
  10. vs201中debug和release两个版本的区别
  11. GoldWave中文版如何将视频批量转换为音频?
  12. 对话行癫:CTO 最重要的是判断未来!| 人物志
  13. 线程分离pthread_detach、pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED);
  14. Tableau笔记(一):tableau 如何绘制环形图
  15. layUI laydate 时间选择器近一天、近一月、近三月、近一年
  16. 亚马逊测评提升销量有什么好办法,分享6点技巧
  17. 计算机的过去和现在作文英语怎么说,自己过去和现在英语作文带翻译
  18. 下载linux系统centos7,CentOS 7.4.1708 下载
  19. dll修复工具哪个比较好?修复工具介绍
  20. 线性数据结构的实现与应用_双端队列_逆波兰式_呼叫中心_XAUAT_(原问题自杜克大学Duke University cps110 C++ Stacks and Queues and Lists)

热门文章

  1. 卓有成效的管理者读后感
  2. 生产型外协管理系统:功能解析篇
  3. VS Visual Studio 魔兽插件开发工具 AddOn Studio for WOW 1 0 含有LUA编辑
  4. 带有非期望产出的SBM模型(python)
  5. 销售订单_跨公司销售
  6. bootstrap5基本使用
  7. 消费者怎么看待 then, catch, finally
  8. 小米android通知栏提示怎么关闭,怎么取消小米音乐自动在通知栏中显示控制开?...
  9. 什么是DDL、DML、DCL、DQL
  10. 可修改性(Mutability)