一:AVL树
AVL树又称平衡搜索二叉树,它能保持二叉树的平衡,降低二叉树的高度,减少树的搜索长度。
AVL树的性质:
1:左子树和右子树的高度差的绝对值不大于1;
2:树中的每个左子树和右子树都是AVL树;
3:树中的每个节点都有平衡因子(_bf),每个平衡因子都等于右子树的高度减去左子树的高度;
例:
二:插入
插入一个节点,可能会对这颗AVL树造成影响,打破平衡,如果要继续满足AVL树的性质,就必须对这棵树进行调整使之重新平衡。
1:当根节点为空,直接插入一个节点,任然平衡。
2:插入一个节点会影响当前节点到根节点的这条路径的平衡因子;
3:当平衡因子是2或者是-2,需要调整使之平衡,当平衡因子是-1,0,1任然是平衡,不需要调整。
三:旋转调整平衡
插入前为平衡因子为1,插入后平衡因子为2需要调整。
1:左单旋:
左单旋是把原subRL做为parent的右子树,parent下调做subR的左子树。
调整前parent->_bf =2,subR->_bf =1;parent要调整,把parent和sunbRL链接,subR和parent链接;这里面有个前提是subRL不为空,否则会出现空指针的访问,因为是三叉链也要对parent的父亲ppnode判断,ppnode为空直接把_root给sunR。调整后ppnode的位置也要调整;更改平衡因子结果为平衡树。
void _RotateL(Node*parent)//左旋
{
//左旋前
Node*subR = parent->_right;
Node*subRL = subR->_left;
parent->_right = subRL;
//parent与subRL相连
if (subRL)
subRL->_parent = parent;
Node*ppnode = parent->_parent;//记住父亲的位置
subR->_left = parent;
parent->_parent = subR;
//subR与ppnode链接
if (ppnode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else
{
if (ppnode->_left ==parent)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
//更新平衡因子
parent->_bf = subR->_bf = 0;
}
2:右旋
插入节点前平衡因子为-1,插入后平衡因子为-2需要调整。
右单旋
右单旋是把原来的parent作为subL的右子树,subL上调作为parent的父亲,
右旋调整是把parent和subL连接起来,再把parent和subLR链接起来,当然也要考虑subLR不为空,才能保证三叉链的合法性,因为是三叉链也要对parent的父亲ppnode判断,ppnode为空直接把_root给sunR。调整后ppnode的位置也要调整; 然后更改平衡因子,使之仍然为AVL树。
右旋的实现:
//右旋
void _RotateR(Node*parent)
{
//右旋前
Node*subL = parent->_left;
Node*subLR = subL->_right;
//parent与subLR相连
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node*ppnode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (ppnode ==NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (ppnode->_left ==parent)
{
ppnode->_left = subL;
}
else
{
ppnode->_right = subL;
}
subL->_parent = ppnode;
}
parent->_bf = subL->_bf = 0;//更新平衡因子
}
3:左右双旋:
左右旋是插入前parent->_bf = -1插入节点后parent->_bf = -2;因此需要调整,可能双旋比较复杂,我们可以看为先左旋然后再右旋,这样就把复杂的问题变简单;我们看它双旋的具体过程:
我们可以分两步
这里我们考虑第一种情况,节点插入到subLR的左边;
第一步先左旋:
右旋
//左右双旋
void _RotateLR(Node*parent)
{
Node*subL = parent->_left;
Node*subLR = subL->_right;
int bf = subLR->_bf;
_RotateL(parent->_left);
_RotateR(parent);
if (bf == 0)
{
parent->_bf = subLR->_bf = subL->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
subLR->_bf = -1;
}
else
{
parent->_bf = 0;
subL->_bf = -1;
subLR->_bf = 1;
}
}
插入节点的情况:分三种情况,(1)插入subLR,(2)插到subLR的左边,(3)插到subLR的右边这三种情况;我们可以用表表示平衡因子的变化
4;右左双旋
我们发现插入节点前parent->_bf =1插入节点后parent->_bf =2;因此需要旋转;类似前面的左右双旋,我们可以把分题化解,先右旋,再左旋,最后调整平衡因子,使之平衡。
我们可以分两步
先右旋:
再左旋
//右左双旋
void _RotateRL(Node*parent)
{
Node*subR = parent->_right;
Node*subRL = subR->_left;
int bf = subRL->_bf;
_RotateR(parent->_right);
_RotateL(parent);
if (bf == 0)
{
parent->_bf = subR->_bf = subRL->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = -1;
}
else
{
parent->_bf = -1;
subR->_bf = 0;
subRL->_bf = 1;
}
}
插入节点的情况:分三种情况,(1)插入subLR,(2)插到subLR的左边,(3)插到subLR的右边这三种情况;我们可以用表表示平衡因子的变化。
四;删除算法:
由前面的插入算法会对平衡因子造成影响,那么删除算法也是如此,当删除的节点,也会对这颗AVL树平衡有影响。这里面主要判断parent节点以及parent节点到根节点,平衡因子的变化。
具体调整平衡因子的方法和Insert相同;
bool _Remove(const K&key)
{
if (_root == NULL)
{
return NULL;
}
Node*cur = _root;
Node*parent = NULL;
while (cur)
{
if (cur->_key < key)//右边
{
parent =cur;
cur = cur->_right;
}
else if (cur->_key>key)//左边
{
parent =cur;
cur = cur->_left;
}
else//查找要删除的位置
{
if (cur->_left == NULL)//左为空
{
if (parent == NULL)
{
_root = cur->_right;
if (cur->_right)//如果cur->_right存在的话就做为根
_root->_parent = NULL;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
parent->_bf++;
}
else
{
parent->_right = cur->_right;
parent->_bf--;
}
}
delete cur;
}
else if (cur->_right == NULL)//右为空
{
if (parent == NULL)
{
_root = cur->_left;
if (cur->_left)//如果cur->_left存在的话就作为根
_root->_parent = NULL;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_left;
parent->_bf--;
}
else
parent->_left = cur->_left;
parent->_bf++;
}
delete cur;
}
else//左右都不为空
{
Node*parent = cur;
Node*subRight = cur->_right;
while (subRight->_left)
{
parent = subRight;
subRight = subRight->_left;
}
parent->_key = subRight->_key;
if (parent->_left == subRight)
{
parent->_left = subRight->_left;
parent->_bf++;
}
else
{
parent->_right = subRight->_right;
parent->_bf--;
}
delete subRight;
}
//删除字数后parent如果不为空向上判断是否平衡
while (parent)//parent不为空可能会不平衡
{
if (parent->_left ==cur)
{
parent->_bf--;
}
else if (parent->_right == cur)
{
parent->_bf++;
}
if (parent->_bf == 0)//根节点
{
return true;
}
else if (parent->_bf == 1 || parent->_bf == -1)//三叉链
{
break;//表示当前已经平衡不需要调整
}
else//-2和2
{
if (parent->_bf == 2)//左旋
{
//左旋分为两种,左单旋和左右双旋
Node*subR = parent->_right;
if (subR->_bf == 1)
{
_RotateL(parent);//左旋
}
else//subR->_bf ==-1;//右左双旋
{
_RotateRL(parent);
}
}
else//parent->_bf==-2右旋
{
//右旋分为右单旋和右左双旋
Node*subL = parent->_left;
if (subL ->_bf == -1)//右单旋
{
_RotateR(parent);
}
else//右左双旋
{
_RotateLR(parent);
}
}
}
}
return true;
}
}
return false;
}
五;判断一棵树是不是AVL树(平衡树)
我们知道AVL树主要是控制高度的,当高度差(平衡因子)的绝对值小于2就默认已经平衡。
前序遍历
size_t Hight(Node*root)
{
if (root == NULL)
{
return 0;
}
int _leftHight = Hight(root->_left);
int _rightHight = Hight(root->_right);
return _leftHight > _rightHight ? (_leftHight + 1) : (_rightHight + 1);
}
//前序O(N^2)
bool _IsBalance(Node*root)
{
if (root == NULL)
{
return true;
}
int left = Hight(root->_left);
int right = Hight(root->_right);
if ((right - left) != root->_bf)
{
cout << "平衡因子失常" << root->_key << endl;
}
return abs(right - left) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right);
}
这种算法时间复杂度 O(N^2)
优化算法:
//后序O(lgN)
bool _IsBalanceOr(Node*root,int &hight)
{
if (root == NULL)
{
hight = 0;
return true;
}
int left, right;
if (_IsBalanceOr(root->_left,left)&& _IsBalanceOr(root->_right,right) && abs(right - left) < 2)
{
hight = left>right ? (left + 1) :( right + 1);
return true;
}
return false;
}
六:完整实现:
.h文件
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode<K, V> *_left;
AVLTreeNode<K, V> *_right;
AVLTreeNode<K, V> *_parent;
K _key;
V _value;
int _bf;//平衡因子
AVLTreeNode(const K&key,const V&value =0)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _bf(0)
{}
};
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V>Node;
public:
AVLTree()
:_root(NULL)
{}
AVLTree(AVLTree<K,V> &tree)//拷贝构造
:_root(NULL)
{
_Copy(_root);
}
AVLTree<K, V>&operator =(AVLTree<K, V>&tree)
{
AVLTree<K, V> tmp(tree);
swap(_root, tree._root);
return *this;
}
~AVLTree()
{
_Destroy(_root);
}
//插入
void Insert(const K&key)
{
_Insert(key);
}
//删除
void Remove(const K&key)
{
_Remove(key);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//判断是不是平衡树(前序)
bool IsBalance()
{
return _IsBalance(_root);
}
//判断是不是平衡树(后序)
bool IsBalanceOr()
{
int hight = 0;
return _IsBalanceOr(_root,hight);
}
protected:
void _InOrder(Node*root)
{
Node*cur = root;
if (cur == NULL)
{
return;
}
_InOrder(cur->_left);
cout << cur->_key << " " ;
_InOrder(cur->_right);
}
//拷贝
void _Copy(Node*root)
{
Node*cur = root;
Node *newNode = NULL;
if (cur)
{
newNode = new Node(cur->_value);
newNode->_left = _Copy(cur->_left);//左边
newNode->_right = _Copy(cur->_right);//右边
}
return newNode;
}
//删除
void _Destroy(Node*root)
{
if (root == NULL)
{
return;
}
Node*cur = root;
_Destroy(cur->_left);
_Destroy(cur->_right);
delete cur;
cur = NULL;
}
bool _Insert(const K&key)
{
if (_root == NULL)
{
_root = new Node(key);
return true;
}
Node*cur = _root;
Node*parent = NULL;
while (cur)
{
if (cur->_key < key)//右边
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key>key)//左边
{
parent = cur;
cur = cur->_left;
}
else
{
return false;//插入的值相等
}
}
cur = new Node(key);//新增节点插入到parent的后面
if (parent->_key < key)//右边
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//插入节点后更新平衡因子
while (parent)//根节点
{
if (parent->_left ==cur)
{
parent->_bf--;
}
else if (parent->_right ==cur)
{
parent->_bf++;
}
if (parent->_bf == 0)//平衡
{
return true;
}
else if (parent->_bf == 1 || parent->_bf == -1)//三叉链
{
cur = parent;
parent = parent->_parent;
}
else//2/-2
{
if (parent->_bf == 2)//左旋
{
//左旋分为左单旋和右左双旋
Node*subR = parent->_right;
if (subR->_bf == 1)
{
_RotateL(parent);//左单旋
return true;
}
else//subR->_bf ==-1
{
_RotateRL(parent);//右左双旋
return true;
}
}
else//parent->_bf == -2//右旋
{
//右旋分为右单旋和左右双旋
Node*subL = parent->_left;
if (subL->_bf == -1)
{
_RotateR(parent);//右单旋
return true;
}
else//subL->_bf ==1;
{
_RotateLR(parent);//左右双旋
return true;
}
}
}
}
return true;
}
bool _Remove(const K&key)
{
if (_root == NULL)
{
return NULL;
}
Node*cur = _root;
Node*parent = NULL;
while (cur)
{
if (cur->_key < key)//右边
{
parent =cur;
cur = cur->_right;
}
else if (cur->_key>key)//左边
{
parent =cur;
cur = cur->_left;
}
else//查找要删除的位置
{
if (cur->_left == NULL)//左为空
{
if (parent == NULL)
{
_root = cur->_right;
if (cur->_right)//如果cur->_right存在的话就做为根
_root->_parent = NULL;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
parent->_bf++;
}
else
{
parent->_right = cur->_right;
parent->_bf--;
}
}
delete cur;
}
else if (cur->_right == NULL)//右为空
{
if (parent == NULL)
{
_root = cur->_left;
if (cur->_left)//如果cur->_left存在的话就作为根
_root->_parent = NULL;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_left;
parent->_bf--;
}
else
parent->_left = cur->_left;
parent->_bf++;
}
delete cur;
}
else//左右都不为空
{
Node*parent = cur;
Node*subRight = cur->_right;
while (subRight->_left)
{
parent = subRight;
subRight = subRight->_left;
}
parent->_key = subRight->_key;
if (parent->_left == subRight)
{
parent->_left = subRight->_left;
parent->_bf++;
}
else
{
parent->_right = subRight->_right;
parent->_bf--;
}
delete subRight;
}
//删除字数后parent如果不为空向上判断是否平衡
while (parent)//parent不为空可能会不平衡
{
if (parent->_left ==cur)
{
parent->_bf--;
}
else if (parent->_right == cur)
{
parent->_bf++;
}
if (parent->_bf == 0)//根节点
{
return true;
}
else if (parent->_bf == 1 || parent->_bf == -1)//三叉链
{
break;//表示当前已经平衡不需要调整
}
else//-2和2
{
if (parent->_bf == 2)//左旋
{
//左旋分为两种,左单旋和左右双旋
Node*subR = parent->_right;
if (subR->_bf == 1)
{
_RotateL(parent);//左旋
}
else//subR->_bf ==-1;//右左双旋
{
_RotateRL(parent);
}
}
else//parent->_bf==-2右旋
{
//右旋分为右单旋和右左双旋
Node*subL = parent->_left;
if (subL ->_bf == -1)//右单旋
{
_RotateR(parent);
}
else//右左双旋
{
_RotateLR(parent);
}
}
}
}
return true;
}
}
return false;
}
size_t Hight(Node*root)
{
if (root == NULL)
{
return 0;
}
int _leftHight = Hight(root->_left);
int _rightHight = Hight(root->_right);
return _leftHight > _rightHight ? (_leftHight + 1) : (_rightHight + 1);
}
protected:
//前序O(N^2)
bool _IsBalance(Node*root)
{
if (root == NULL)
{
return true;
}
int left = Hight(root->_left);
int right = Hight(root->_right);
if ((right - left) != root->_bf)
{
cout << "平衡因子失常" << root->_key << endl;
}
return abs(right - left) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right);
}
//后序O(lgN)
bool _IsBalanceOr(Node*root,int &hight)
{
if (root == NULL)
{
hight = 0;
return true;
}
int left, right;
if (_IsBalanceOr(root->_left,left)&& _IsBalanceOr(root->_right,right) && abs(right - left) < 2)
{
hight = left>right ? (left + 1) :( right + 1);
return true;
}
return false;
}
void _RotateL(Node*parent)//左旋
{
//左旋前
Node*subR = parent->_right;
Node*subRL = subR->_left;
parent->_right = subRL;
//parent与subRL相连
if (subRL)
subRL->_parent = parent;
Node*ppnode = parent->_parent;//记住父亲的位置
subR->_left = parent;
parent->_parent = subR;
//subR与ppnode链接
if (ppnode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else
{
if (ppnode->_left ==parent)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
//更新平衡因子
parent->_bf = subR->_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 == 0)
{
parent->_bf = subLR->_bf = subL->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
subLR->_bf = -1;
}
else
{
parent->_bf = 0;
subL->_bf = -1;
subLR->_bf = 1;
}
}
//右旋
void _RotateR(Node*parent)
{
//右旋前
Node*subL = parent->_left;
Node*subLR = subL->_right;
//parent与subLR相连
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node*ppnode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (ppnode ==NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (ppnode->_left ==parent)
{
ppnode->_left = subL;
}
else
{
ppnode->_right = subL;
}
subL->_parent = ppnode;
}
parent->_bf = subL->_bf = 0;//更新平衡因子
}
//右左双旋
void _RotateRL(Node*parent)
{
Node*subR = parent->_right;
Node*subRL = subR->_left;
int bf = subRL->_bf;
_RotateR(parent->_right);
_RotateL(parent);
if (bf == 0)
{
parent->_bf = subR->_bf = subRL->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = -1;
}
else
{
parent->_bf = -1;
subR->_bf = 0;
subRL->_bf = 1;
}
}
protected:
Node*_root;
};
void TestAVLTree1()
{
AVLTree<int, int> t;
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
t.Insert(a[i]);
}
t.InOrder();
cout <<"IsBalance?"<<t.IsBalance()<< endl;
cout << "IsBalanceOr?" << t.IsBalanceOr() << endl;
t.Remove(16);
t.Remove(3);
t.Remove(7);
t.Remove(11);
t.InOrder();//9, 26, 18, 14, 15
cout << "IsBalance?" << t.IsBalance() << endl;
cout << "IsBalanceOr?" << t.IsBalanceOr() << endl;
t.Remove(9);
t.Remove(26);
t.Remove(18);
t.Remove(15);
t.Remove(14);
t.InOrder();
}
void TestAVLTree2()
{
AVLTree<int, int> t;
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
t.Insert(a[i]);
}
t.InOrder();
cout << "IsBalance?" << t.IsBalance() << endl;
cout << "IsBalanceOr?" << t.IsBalanceOr() << endl;
}
.cpp文件
#include<iostream>
#include"AVLTree.h"
using namespace std;
int main()
{
TestAVLTree1();
TestAVLTree2();
system("pause");
return 0;
}