平衡二叉树AVL—tree
树中每一个节点左右孩子的高度差不超过1的有序二叉树(左右孩子的高度差)
这种也是平衡二叉树
为什么学习平衡二叉树?
先问一个问题:下面这个有序二叉树的查找效率高还是不高?
答案是不高。
举个例子:
就好像担当子,要左右平衡才好担,二叉树同样如此,要左右平滑才好查找。
看如图:我们要查找最下方的1,左边和右边各要查找的次数是多少?
答案:左边查找1,找6次,右边查找1,找4次
所以要查找效率高一点,就希望是右边这种树
所以有了新的概念,高度:距离根节点有多少层
(查找数据的高度)如:根为1,根孩子:2,根孩子的孩子:3
那么如何做出平衡二叉树?旋转!
- 有序二叉树方式插入节点
- 判断是否平衡(左右高度差是否超过1)
如果平衡 设置高度
如果不平衡 用旋转(不平衡变平衡) 设置高度
不平衡的四种情况:
判断是那种情况导致的不平衡,在针对这种情况
第一种:以当前节点的父节点(11)右旋
第二种:以当前节点的父节点(11)左旋
第三种:(左右旋)先以当前节点(10)左旋,然后以当前节点的父节点(11)为轴右旋
第四种:(右左旋)先以当前节点(10)左旋,然后以当前节点的父节点(11)为轴右旋
右旋原理
左旋原理
代码:
头文件:
#pragma once
#include <iostream>
using namespace std;
//节点类型
template<class T>
struct treeNode
{
T data; //数据
treeNode* pLeft; //左孩子
treeNode* pRight; //右孩子
int height; //高度
treeNode(const T& data)
{
this->data = data;
pLeft = pRight = NULL;
height = 0;
}
};
template<class T>
class myAVLtree
{
public:
treeNode<T>* pRoot;//指向根节点的指针
public:
myAVLtree() { pRoot = NULL; }
~myAVLtree(){}
void insertNode(const T& data);
private:
void _insertNode(treeNode<T>*& root, const T& data);
//获取某节点高度
int _getNodeHeight(treeNode<T>* root);
//旋转的代码要是以谁为轴,所以单独写
//右旋
treeNode<T>* rightRotator(treeNode<T>* root);
//左旋
treeNode<T>* leftRotator(treeNode<T>* root);
//左右旋
treeNode<T>* LRRotator(treeNode<T>* root);
//右左旋
treeNode<T>* RLRotator(treeNode<T>* root);
};
//public 函数
template<class T>
void myAVLtree<T>::insertNode(const T& data)
{
_insertNode(pRoot, data);
}
//private 函数
//添加函数
template<class T>
void myAVLtree<T>::_insertNode(treeNode<T>*& root, const T& data)
{
//先用有序二叉树的插入
if (root==NULL)
{
root = new treeNode<T>(data);
}
else if (data<root->data)//左子树进行插入
{
_insertNode(root->pLeft,data);
//判断是否平衡
if ((_getNodeHeight(root->pLeft) - _getNodeHeight(root->pRight))>1)
{
//这就只有1,3两种情况
if (data<root->pLeft->data)//情况一 需要右旋
{
root=rightRotator(root);
}
else//情况三 需要左右旋
{
root=LRRotator(root);
}
}
}
else//右子树进行插入
{
_insertNode(root->pRight, data);
//判断是否平衡
if ((_getNodeHeight(root->pRight) - _getNodeHeight(root->pLeft)) > 1)
{
//这就只有2,4两种情况
if (data >= root->pRight->data)//情况二 需要左旋
{
root=leftRotator(root);
}
else//情况四 需要右左旋
{
root=RLRotator(root);
}
}
}
//上面旋转完之后要记得设置高度,高度是会变的
int leftHeight=_getNodeHeight(root->pLeft);
int rightHeight = _getNodeHeight(root->pRight);
root->height = 1 + ((leftHeight > rightHeight) ? leftHeight : rightHeight);
}
//获取某节点高度
template<class T>
int myAVLtree<T>::_getNodeHeight(treeNode<T>* root)
{
if (root)
{
return root->height;
}
return 0;
}
//右旋
template<class T>
treeNode<T>* myAVLtree<T>::rightRotator(treeNode<T>* root)
{
//1.pTemp存储
treeNode<T>* pTemp = root->pLeft;
//2.让temp的右孩子成为root的左孩子
root->pLeft = pTemp->pRight;
//3.root成为temp的右孩子
pTemp->pRight= root;
//4.设置高度
root->height = 1 + ((_getNodeHeight(root->pLeft) > _getNodeHeight(root->pRight))?
_getNodeHeight(root->pLeft): _getNodeHeight(root->pRight));
//temp的高度也要变
pTemp->height = 1 + ((_getNodeHeight(pTemp->pLeft) > _getNodeHeight(pTemp->pRight)) ?
_getNodeHeight(pTemp->pLeft) : _getNodeHeight(pTemp->pRight));
//5.return temp
return pTemp;
}
//左旋
template<class T>
treeNode<T>* myAVLtree<T>::leftRotator(treeNode<T>* root)
{
//1.pTemp存储
treeNode<T>* pTemp = root->pRight;
//2.让temp的左孩子成为root的右孩子
root->pRight = pTemp->pLeft;
//3.root成为temp的左孩子
pTemp->pLeft = root;
//4.设置高度
root->height = 1 + ((_getNodeHeight(root->pLeft) > _getNodeHeight(root->pRight)) ?
_getNodeHeight(root->pLeft) : _getNodeHeight(root->pRight));
//temp的高度也要变
pTemp->height = 1 + ((_getNodeHeight(pTemp->pLeft) > _getNodeHeight(pTemp->pRight)) ?
_getNodeHeight(pTemp->pLeft) : _getNodeHeight(pTemp->pRight));
//5.return temp
return pTemp;
}
//左右旋
template<class T>
treeNode<T>* myAVLtree<T>::LRRotator(treeNode<T>* root)
{
//以root的左孩子为轴左旋
root->pLeft = leftRotator(root->pLeft);
//以root为轴右旋
return rightRotator(root);
}
//右左旋
template<class T>
treeNode<T>* myAVLtree<T>::RLRotator(treeNode<T>* root)
{
//以root的右孩子为轴右旋
root->pRight = rightRotator(root->pRight);
//以root为轴左旋
return leftRotator(root);
}
源文件:
#include "AVL_tree.h"
int main()
{
int arr[10] = { 11,66,55,77,88,12,33,46,84,13 };
myAVLtree<int> tree;
for (int i = 0; i < 10; i++)
{
tree.insertNode(arr[i]);
}
while (1)
{
}
return 0;
}