实现AVL树
一.为什么需要平衡二叉搜索树(AVL树)?
1.简单引入:
1,在正常的二叉搜索树中存在插入数据按照二叉搜索树的规则为单枝的情况。
2.假设插入了N个数据在二叉搜索树中这N个数据都是在一个单枝上面。
3.进行find操作找道一个数据从正常搜索树的高度次变成了N次。
2.AVL树的性质:
1.AVL树的子树都必须是AVL树:
2.左右子树的高度差不超过1,当前树就是一个二叉搜索树。
3.AVL树满足二叉搜索树的所有性质:
3.通过什么方式去控制高度差?
平衡因子:
1.平衡因子记录当前节点的左右子树的高度差值。
2.平衡因子的值默认为:右子树高度减左子树高度。
4. 基本结构:
template<class T>
struct AVLTreeNode {
typedef AVLTreeNode<T>* Node;
typedef T date;
//1.构造函数:
AVLTreeNode()
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_date(date())
,_bf(0)
Node _left;//左子树
Node _right;//右子树
Node _parent;//节点的父节点
date _date;//数据
int _bf;//平衡因子
};
为什么考虑加入一个当前节点的父节点呢?
1.当前节点的左右高度差变化有可能会影响当前节点父节点的平衡因子的变化:
2.考虑在节点中加一个父节点的指针。
二.实现AVL树:
0.中序遍历
1.验证树是否为二叉搜索树。
2.同时打印平衡因子:
//中序遍历:
void _Inorder(Node cur)
{
if (cur == nullptr)
return;
_Inorder(cur->_left);
cout << "date:" << cur->_date << "平衡因子:" << cur->_bf << endl;
_Inorder(cur->_right);
}
void Inorder()
{
if (_root == nullptr)
return;
_Inorder(_root);
}
1.实现简单情况插入:
1.不影响爷爷节点:
2.影响爷爷节点为1/-1:
//1.当前二叉树中没有元素:
if (_root == nullptr)
{
Node newnode = new AVLTreeNode<T>(date);
_root = newnode;
}
//2.当前二叉树中有元素:
else
{
//1.遍历找插入位置:
Node cur = _root;
Node prev = nullptr;
while (cur != nullptr)
{
prev = cur;
if (cur->_date > date)
{
cur = cur->_left;
}
else if (cur->_date < date)
{
cur = cur->_right;
}
else
{
return false;
}
}
cur = new AVLTreeNode<T>(date);
if (cur->_date > prev->_date)
{
prev->_right = cur;
}
else if (cur->_date < prev->_date)
{
prev->_left = cur;
}
cur->_parent = prev;
//2.进行节点插入和平衡因子修改:
//2-1:正常插入:右减左
//右插入--->_bf++
//左插入--->_bf--
//节点插入判断左右:当前节点左右都为空或者有一个为空进行判断!
while (prev)
{
//左插
if (prev->_left == cur)
{
(prev->_bf)--;
}
//右插
else if (prev->_right == cur)
{
(prev->_bf)++;
}
//1.平衡了
if (prev->_bf == 0)
{
break;
}
//2.爷爷节点被影响,向上进行调整。
else if (prev->_bf == 1 || prev->_bf == -1)
{
cur = cur->_parent;
prev = prev->_parent;
}
//3.旋转判断
else if (prev!=nullptr && (prev->_bf == -2 || prev->_bf ==2))
{
}
}
}
return true;
}
2.实现旋转操作解决插入节点产生-2/2的情况:
1.旋转的意义:
1.保持搜索树的规则:
2.当前树丛不平衡道平衡:
3.降低当前树的高度:
2.左旋:
当h为1的时候:
//左旋:
void left_turn(Node& parent)
{
Node subR = parent->_right;
Node subRL = subR->_left;
parent->_right = subRL;
//特殊情况的判断:
if (subRL != nullptr)
subRL->_parent = parent;
Node ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
//当前的parent是子树还是根
//1.作为根:
if (ppNode == nullptr)
_root = subR;
//2.作为子树考虑左右
else
{
if (ppNode->_left == parent)
ppNode->_left = subR;
else if (ppNode->_right == parent)
ppNode->_right = subR;
}
subR->_parent = ppNode;
//考虑平衡因子变化:
parent->_bf = 0;
subR->_bf = 0;
}
3.右旋:
当h为1的时候:
//右旋:
void right_turn(Node& parent)
{
Node subL = parent->_left;
Node subLR = subL->_right;
parent->_left = subLR;
//特殊情况的判断:
if (subLR != nullptr)
subLR->_parent = parent;
Node ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
//当前的parent是子树还是根
//1.作为根:
if (ppNode == nullptr)
_root = subL;
//2.作为子树考虑左右
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else if (ppNode->_right == parent)
ppNode->_right = subL;
}
subL->_parent = ppNode;
//考虑平衡因子变化:
parent->_bf = 0;
subL->_bf = 0;
}
4.左右旋转:
//左+右:
void left_right_turn(Node& parent)
{
void left_right_turn(Node& parent)
{
Node subL = parent->_left;
Node subLR = subL->_right;
//记录节点的平衡因子确定是左边还是右边
int bf = subLR->_bf;
//1.右左双旋:
right_turn(parent->_left);
left_turn(parent);
//2.平衡因子的变换--->不进行后续操作会变成全零:
//右有
if (bf == 1)
{
subL->_bf = 0;
parent->_bf = 1;
}
//左有
else if (bf == -1)
{
subL->_bf = -1;
parent->_bf = 0;
}
//没有
else if (bf == 0)
{
subL->_bf = 0;
parent->_bf = 0;
}
}
5.右左旋转:
void right_left_turn(Node& parent)
{
Node subR = parent->_right;
Node subRL = subR->_left;
//记录节点的平衡因子确定是左边还是右边
int bf = subRL->_bf;
//1.右左双旋:
right_turn(parent->_right);
left_turn(parent);
//2.平衡因子的变换--->不进行后续操作会变成全零:
//右有
if (bf == 1)
{
//subR->_bf = 0;
//parent->_bf = -1;
}
//左有
else if (bf == -1)
{
//subR->_bf = 1;
//parent->_bf = 0;
}
//没有
else if (bf == 0)
{
//subR->_bf = 0;
//parent->_bf = 0;
}
}
3.计算子树高度:
int _hight(Node root)
{
if (root == nullptr)
return 0;
int hight_left = _hight(root->_left);
int hight_right = _hight(root->_right);
return (hight_left > hight_right ? hight_left + 1 : hight_right + 1);
}
int hight()
{
return _hight(_root);
}
4.判断当前avl树是否正确:
bool _isbalanceavl(Node root , int& hight)
{
//使用后续遍历+返回形参数:
if (root == nullptr)
{
hight = 0;
return true;
}
int hight_left, hight_right = 0;
if ((!_isbalanceavl(root->_left,hight_left))
|| (!_isbalanceavl(root->_right,hight_right)))
{
return false;
}
if (abs(hight_right - hight_left) >= 2)
{
cout << "数据:" << root->_date << " hight:" << hight_right - hight_left << " 平衡因子:" << root->_bf << "不平衡" << endl;
return false;
}
else if (hight_right-hight_left != root->_bf)
{
cout << "数据:" << root->_date << " hight:" << hight_right - hight_left << " 平衡因子:" << root->_bf << "平衡因子异常" << endl;
return false;
}
hight = (hight_left > hight_right ? hight_left + 1 : hight_right + 1);
return true;
}
bool isbalanceavl()
{
int hight = 0;
return _isbalanceavl(_root,hight);
}