高度平衡二叉搜索树(AVLTree)
高度平衡二叉搜索树(AVLTree)
目录
- AVL树的概念
- AVL树节点的定义
- AVL树的插入
- AVL树的旋转
- 右单旋
- 左单旋
- 左右双旋
- 右左双旋
- AVL树的验证
- 代码实现
AVL树的概念
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1,平衡因子的求法=右子树高度-左子树的高度
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O(log2N),搜索时间复杂度O( log2N)。
AVL树节点的定义
AVL树的插入
AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么AVL树的插入过程可以分为两步:
1. 按照二叉搜索树的方式插入新节点
2. 调整节点的平衡因子
pair<Node*, bool> Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return make_pair(_root, true);}// 找到存储位置,把数据插入进去Node* parent = _root, *cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return make_pair(cur, true);}}cur = new Node(kv);Node* newnode = cur;if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}// 控制平衡// 1、更新平衡因子// 2、如果出现不平衡,则需要旋转//while (parent)while (cur != _root){if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){// parent所在的子树高度变了,会影响parent->parent// 继续往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//parent所在子树已经不平衡,需要旋转处理一下if (parent->_bf == -2){if (cur->_bf == -1){// 右单旋RotateR(parent);}else // cur->_bf == 1{RotateLR(parent);}}else // parent->_bf == 2{if (cur->_bf == 1){// 左单旋RotateL(parent);}else // cur->_bf == -1{RotateRL(parent);}}break;}else{// 插入节点之前,树已经不平衡了,或者bf出错。需要检查其他逻辑assert(false);}}return make_pair(newnode, true);}
AVL树的旋转
如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:
1. 新节点插入较高左子树的左侧—左左:右单旋
2. 新节点插入较高右子树的右侧—右右:左单旋
3. 新节点插入较高左子树的右侧—左右:先左单旋再右单旋
4. 新节点插入较高右子树的左侧—右左:先右单旋再左单旋
右单旋
void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* parentParent = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;_root->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;}subL->_bf = parent->_bf = 0;}
左单旋
void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* parentParent = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;_root->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;}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);// ...平衡因子调节还需要具体分析if (bf == -1){subL->_bf = 0;parent->_bf = 1;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else if (bf == 0){parent->_bf = 0;subL->_bf = 0;subLR->_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);// 平衡因子更新if (bf == 1){subR->_bf = 0;parent->_bf = -1;subRL->_bf = 0;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else if (bf == 0){parent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else{assert(false);}}
AVL树的验证
AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:
验证其为二叉搜索树
如果中序遍历可得到一个有序的序列,就说明为二叉搜索树验证其为平衡树
每个节点子树高度差的绝对值不超过1
void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":"<<root->_kv.second<<endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);}int _Height(Node* root){if (root == nullptr){return 0;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;}bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 检查一下平衡因子是否正确if (rightHeight - leftHeight != root->_bf){cout << "平衡因子异常:"<<root->_kv.first<<endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}bool IsAVLTree(){return _IsBalance(_root);}
代码实现
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;// 右子树的高度-左子树的高度int _bf; // 平衡因子 balance factorpair<K, V> _kv;AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0), _kv(kv){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:AVLTree():_root(nullptr){}// 拷贝构造和赋值需要实现深拷贝void _Destory(Node* root){if (root == nullptr){return;}_Destory(root->_left);_Destory(root->_right);delete root;}~AVLTree(){_Destory(_root);_root = nullptr;}V& operator[](const K& key){pair<Node*, bool> ret = Insert(make_pair(key, V()));return ret.first->_kv.second;}pair<Node*, bool> Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return make_pair(_root, true);}// 找到存储位置,把数据插入进去Node* parent = _root, *cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return make_pair(cur, true);}}cur = new Node(kv);Node* newnode = cur;if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}// 控制平衡// 1、更新平衡因子// 2、如果出现不平衡,则需要旋转//while (parent)while (cur != _root){if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){// parent所在的子树高度变了,会影响parent->parent// 继续往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//parent所在子树已经不平衡,需要旋转处理一下if (parent->_bf == -2){if (cur->_bf == -1){// 右单旋RotateR(parent);}else // cur->_bf == 1{RotateLR(parent);}}else // parent->_bf == 2{if (cur->_bf == 1){// 左单旋RotateL(parent);}else // cur->_bf == -1{RotateRL(parent);}}break;}else{// 插入节点之前,树已经不平衡了,或者bf出错。需要检查其他逻辑assert(false);}}return make_pair(newnode, true);}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);// ...平衡因子调节还需要具体分析if (bf == -1){subL->_bf = 0;parent->_bf = 1;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else if (bf == 0){parent->_bf = 0;subL->_bf = 0;subLR->_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);// 平衡因子更新if (bf == 1){subR->_bf = 0;parent->_bf = -1;subRL->_bf = 0;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else if (bf == 0){parent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else{assert(false);}}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL){subRL->_parent = parent;}subR->_left = parent;Node* parentParent = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* parentParent = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;_root->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;}subL->_bf = parent->_bf = 0;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return cur;}}return nullptr;}// 1、工作中会用的(AVL树不会自己写,这里通过插入深入理解一下他的性质就够了)// 2、校招会考的(基本不会问删除的细节)// 有兴趣的可以下去实现一下。bool Erase(const K& key){return false;}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":"<<root->_kv.second<<endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);}int _Height(Node* root){if (root == nullptr){return 0;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;}bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 检查一下平衡因子是否正确if (rightHeight - leftHeight != root->_bf){cout << "平衡因子异常:"<<root->_kv.first<<endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}bool IsAVLTree(){return _IsBalance(_root);}
private:Node* _root;
};
高度平衡二叉搜索树(AVLTree)相关推荐
- 每天一道LeetCode-----将有序序列转成高度平衡二叉搜索树
Convert Sorted Array to Binary Search Tree 原题链接Convert Sorted Array to Binary Search Tree 给定一个地增序列,要 ...
- 《恋上数据结构第1季》平衡二叉搜索树、AVL树
AVL树 二叉搜索树缺点分析 改进二叉搜索树 平衡(Balance) 理想平衡 如何改进二叉搜索树? 平衡二叉搜索树(Balanced Binary Search Tree) AVL树 BST 对比 ...
- 数据结构与算法-平衡二叉搜索树
平衡二叉搜索树 1.自平衡的二叉搜索树 2.平衡 (1)空树平衡 (2)非空树平衡 左右子树平衡 左右子树高度差绝对值 <= 1 3.平衡因子 左右子树的高度差的衡量值 -1 0 1 (一)平衡 ...
- VC++2012编程演练数据结构《9》平衡二叉搜索树
平衡二叉搜索树 任何结点的左子树和右子树高度最多相差1的二叉搜索树. (1)AVL树的插入算法 a. 插入结点之后仍然是AVL树,则不调整: b. 插入结点之后不再满足AVL树条件,则进行调整,根据导 ...
- 二叉搜索树、平衡二叉搜索树和红黑树
文章目录 一. 二叉搜索树(Binary Sort Tree) 二. 二叉平衡搜索树(AVL) 三. 红黑树 一. 二叉搜索树(Binary Sort Tree) 二叉搜索树,又称为二叉排序树(二叉查 ...
- 五.树,二叉树,二叉搜索树(BST)和自平衡二叉搜索树(AVL)
1.树 树是一种数据结构 比如:目录结构 树是一种可以递归定义的数据结构 树是由n个节点组成的集合: 如果 n=0, 那这是一颗空树 如果 n>0, 那存在1个节点作为树的根节点,其他节点可以分 ...
- 看动画学算法之:平衡二叉搜索树AVL Tree
简介 平衡二叉搜索树是一种特殊的二叉搜索树.为什么会有平衡二叉搜索树呢? 考虑一下二叉搜索树的特殊情况,如果一个二叉搜索树所有的节点都是右节点,那么这个二叉搜索树将会退化成为链表.从而导致搜索的时间复 ...
- 牛客题霸 [将升序数组转化为平衡二叉搜索树]C++题解/答案
牛客题霸 [将升序数组转化为平衡二叉搜索树]C++题解/答案 题目描述 给出一个升序排序的数组,将其转化为平衡二叉搜索树(BST). 题解: 二叉搜索树的定义: 二叉搜索树或者是一棵空树,或者是具有下 ...
- 红黑树 平衡二叉搜索树_红黑树:自我平衡的二叉搜索树,并举例说明
红黑树 平衡二叉搜索树 什么是红黑树? (What is a Red-Black Tree?) Red-Black Tree is a type of self-balancing Binary Se ...
最新文章
- 编写一个程序,实现将c语言源程序中的注释全部删除
- 团队作业1(陈爽、夏江华、李瑞超、甘彩娈、吕乐乐)
- mysql 值为0 但却被认为null_MySQL介于普通读和锁定读的加锁方式
- 代码抽象_如何通过抽象使代码更具可读性
- 同步服务器客户端位置,服务器和客户端信息同步方式
- Android 教你打造炫酷的ViewPagerIndicator
- 2012年参加油田象棋比赛的几盘棋
- html网页设计语言基础教程,HTML 网页设计新手入门教程(共32课时)_IT教程网
- 期货交易常用术语英语词汇
- 锦天科技被盛大收购 23岁创始人成亿万富翁
- android 看电脑视频,超级看电脑在线观看方法教程详解_丝瓜视频安卓版
- Scrapy框架学习 - 爬取豆瓣电影排行榜TOP250所有电影信息并保存到MongoDB数据库中
- 解读6大常见肿瘤的消融选择
- 想象力的再突破!无人机后还有大招?!
- Oracle精髓(第4版)
- 为什么现在还有985高校给大一上C语言课?
- Spring Boot2 redis
- Android菜鸟的成长笔记(3)——给QQ登录界面说So Easy
- numpy.corrcoef()函数讲解
- Keil5可以打开Keil4