平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。
平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。
但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。
平衡二叉树实现的大部分过程和二叉查找树是一样的(学平衡二叉树之前一定要会二叉查找树),区别就在于插入和删除之后要写一个旋转算法去维持平衡,维持平衡需要借助一个节点高度的属性。
讲解视频:链接:https://pan.baidu.com/s/1w5hlEwgbG7qFF7ZJr52QmA 提取码:mhmw
#pragma once
//二叉树节点
template<class T>
struct BinaryNode
{
T mValue;
int mHeight; //树的高度
BinaryNode<T>* pLchild; //指向左子树节点
BinaryNode<T>* pRchild; //指向右子树节点
BinaryNode<T>* pParent; //指向父节点
};
template<class T>
class BinarySearchTree
{
public:
// 构造函数
BinarySearchTree();
// 析构函数
~BinarySearchTree();
// 拷贝构造函数
BinarySearchTree(const BinarySearchTree<T>& bst);
//插入
void Insert(const T& val);
//查找
BinaryNode<T>* SearchNode(const T& val);
// 中序遍历
template<class _Func>
void Foreach(_Func func);
// 辅助中序遍历
template<class _Func>
void MyForeach(BinaryNode<T>* root, _Func func);
//释放二叉树
void MyFree(BinaryNode<T>* root)l;
//拷贝二叉树
BinaryNode<T>* MyCopy(BinaryNode<T>* root, BinaryNode<T>* parent = NULL);
//删除算法
void Remove(const T& val);
//第一种情况,如果删除的结点是叶子节点
void RemoveNoChildNode(BinaryNode<T>* delNode);
//第二种情况,如果删除的结点只有一个孩子
void RemoveSingleChildNode(BinaryNode<T>* delNode);
//第三种情况,如果删除的结点有两个孩子
void RemoveDoubleChildNode(BinaryNode<T>* delNode);
//获得最大值结点
BinaryNode<T>* GetMaxNode(BinaryNode<T>* root);
//获得最小值结点
BinaryNode<T>* GetMinNode(BinaryNode<T>* root);
/* 平衡二叉树接口 */
//更新树的高度
int UpdateTreeHeight(BinaryNode<T>* root);
//获得某个子树的高度
int GetTreeHeight(BinaryNode<T>* node);
//求某个子树的平衡因子
int GetBalanceFactor(BinaryNode<T>* node);
// 右旋
void RightRotate(BinaryNode<T>* node);
// 左旋
void leftRotate(BinaryNode<T>* node);
// 调整树的平衡(subRoot)
void AdjustTreeBalance(BinaryNode<T>* subRoot);
public:
BinaryNode<T>* pRoot; //永远指向二叉排序树的根节点
int mSize;
};
1. 初始化和销毁
// 构造函数
template<class T>
BinarySearchTree<T>::BinarySearchTree()
{
pRoot = NULL;
mSize = 0;
}
// 析构函数
template<class T>
BinarySearchTree<T>::~BinarySearchTree()
{
MyFree(pRoot);
}
// 拷贝构造
template<class T>
BinarySearchTree<T>::BinarySearchTree(const BinarySearchTree<T>& bst)
{
mSize = bst.mSize;
pRoot = MyCopy(bst.pRoot, NULL);
}
//释放二叉树
template<class T>
void BinarySearchTree<T>::MyFree(BinaryNode<T>* root)
{
if (NULL == root)
{
return;
}
//释放左子树内存
MyFree(root->pLchild);
//释放右子树内存
MyFree(root->pRchild);
//释放当前结点的内存
delete root;
}
//拷贝二叉树
template<class T>
BinaryNode<T>* BinarySearchTree<T>::MyCopy(BinaryNode<T>* root, BinaryNode<T>* parent = NULL)
{
if (NULL == root)
{
return NULL;
}
//拷贝当前结点
BinaryNode<T>* newnode = new BinaryNode<T>;
newnode->mValue = root->mValue;
newnode->pParent = parent;
newnode->pLchild = NULL;
newnode->pRchild = NULL;
//拷贝左子树
BinaryNode<T>* pLeft = MyCopy(root->pLchild, newnode);
//拷贝右子树
BinaryNode<T>* pRight = MyCopy(root->pRchild, newnode);
//更新新节点的左右指针指向
newnode->pLchild = pLeft;
newnode->pRchild = pRight;
return newnode;
}
2. 遍历函数
template<class T> template<class _Func>
void BinarySearchTree<T>::Foreach(_Func func)
{
MyForeach(pRoot, func);
}
//辅助中序遍历
template<class T> template<class _Func>
void BinarySearchTree<T>::MyForeach(BinaryNode<T>* root, _Func func)
{
if (NULL == root)
{
return;
}
MyForeach(root->pLchild, func);
func(root->mValue);
MyForeach(root->pRchild, func);
}
3. 查找函数
template<class T>
BinaryNode<T>* BinarySearchTree<T>::SearchNode(const T& val)
{
//辅助指针变量
BinaryNode<T>* pCurrent = pRoot;
while (pCurrent != NULL)
{
if (val < pCurrent->mValue)
{
pCurrent = pCurrent->pLchild;
}
else if (!(val < pCurrent->mValue) && !(pCurrent->mValue < val))
{
return pCurrent;
}
else
{
pCurrent = pCurrent->pRchild;
}
}
return NULL;
}
4. 树高度函数
//获得子树的高度
template<class T>
int BinarySearchTree<T>::GetTreeHeight(BinaryNode<T>* node)
{
if (NULL == node)
{
return 0;
}
return node->mHeight;
}
//求某个子树的平衡因子
template<class T>
int BinarySearchTree<T>::GetBalanceFactor(BinaryNode<T>* node)
{
if (NULL == node)
{
return 0;
}
return GetTreeHeight(node->pLchild) - GetTreeHeight(node->pRchild);
}
5. 树旋转操作
//树的旋转-向右旋转
template<class T>
void BinarySearchTree<T>::RightRotate(BinaryNode<T>* node)
{
if (NULL == node)
{
return;
}
//缓存下当前子树的根节点的父节点
BinaryNode<T>* pParent = node->pParent;
//缓存下当前子树的根节点的左子树
BinaryNode<T>* pLeftNode = node->pLchild;
node->pLchild = pLeftNode->pRchild;
if (pLeftNode->pRchild != NULL)
{
pLeftNode->pRchild->pParent = node;
}
pLeftNode->pRchild = node;
node->pParent = pLeftNode;
//备注:设置父节点
pLeftNode->pParent = pParent;
//父节点为NULL
if (pParent == NULL)
{
pRoot = pLeftNode;
}
else
{
if (pParent->pLchild == node)
{
pParent->pLchild = pLeftNode;
}
else
{
pParent->pRchild = pLeftNode;
}
}
}
//左旋
template<class T>
void BinarySearchTree<T>::leftRotate(BinaryNode<T>* node)
{
if (NULL == node)
{
return;
}
//缓存下父节点
BinaryNode<T>* pParent = node->pParent;
//缓存下右子树
BinaryNode<T>* pRight = node->pRchild;
node->pRchild = pRight->pLchild;
if (pRight->pLchild != NULL)
{
pRight->pLchild->pParent = node;
}
pRight->pLchild = node;
node->pParent = pRight;
//备注:设置父节点
pRight->pParent = pParent;
if (pParent == NULL)
{
pRoot = pRight;
}
else
{
if (pParent->pLchild == node)
{
pParent->pLchild = pRight;
}
else
{
pParent->pRchild = pRight;
}
}
}
//调整树的平衡(subRoot)
template<class T>
void BinarySearchTree<T>::AdjustTreeBalance(BinaryNode<T>* subRoot)
{
if (NULL == subRoot)
{
return;
}
//找到最小不平衡子树
BinaryNode<T>* pBack = subRoot;
//当前结点的平衡因子
int factor = 0;
while (pBack != NULL)
{
//计算当前结点的平衡因子
factor = GetBalanceFactor(pBack);
if (abs(factor) > 1)
{
break;
}
pBack = pBack->pParent;
}
if (pBack == NULL)
{
//此时树不需要调整
return;
}
if (factor > 1)
{
//右旋
if (GetBalanceFactor(pBack->pLchild) > 0)
{
//进行一次向右旋转
RightRotate(pBack);
}
else
{
//先把pBack->pLchild左旋一次
leftRotate(pBack->pLchild);
//再把pBack整体向右旋转一次
RightRotate(pBack);
}
}
else
{
//左旋
if (GetBalanceFactor(pBack->pRchild) < 0)
{
//直接向左旋转一次
leftRotate(pBack);
}
else
{
//先把pBack->pRcild向右旋转一次
RightRotate(pBack->pRchild);
//然后再把pBack整体向左旋转一次
leftRotate(pBack);
}
}
}
6. 插入函数
//插入
template<class T>
void BinarySearchTree<T>::Insert(const T& val)
{
if (SearchNode(val))
{
cout << "节点存在,拒绝插入!" << endl;
}
//指向插入位置的父节点
BinaryNode<T>* pInsertNode = NULL;
//指向当前结点
BinaryNode<T>* pCurrent = pRoot;
while (pCurrent != NULL)
{
pInsertNode = pCurrent;
if (val < pCurrent->mValue)
{
pCurrent = pCurrent->pLchild;
}
else
{
pCurrent = pCurrent->pRchild;
}
}
//创建新节点
BinaryNode<T>* newnode = new BinaryNode<T>;
newnode->mValue = val;
newnode->pLchild = NULL;
newnode->pRchild = NULL;
newnode->pParent = pInsertNode;
//判断pInsertNode是否是NULL,如果为NULL,说明当前树是一个空树
if (pInsertNode == NULL)
{
pRoot = newnode;
}
else
{
if (val < pInsertNode->mValue)
{
pInsertNode->pLchild = newnode;
}
else
{
pInsertNode->pRchild = newnode;
}
}
++mSize;
//更新树的高度
UpdateTreeHeight(pRoot);
//调整树的平衡
AdjustTreeBalance(newnode->pParent);
}
7. 删除函数
//删除算法
template<class T>
void BinarySearchTree<T>::Remove(const T& val)
{
BinaryNode<T>* pDelNode = SearchNode(val);
if (pDelNode == NULL)
{
cout << "删除的结点不存在!" << endl;
return;
}
//第一种情况,删除节点是叶子节点
if (pDelNode->pLchild == NULL && pDelNode->pRchild == NULL)
{
RemoveNoChildNode(pDelNode);
}
//第三种情况,删除节点有两个孩子
else if (pDelNode->pLchild != NULL && pDelNode->pRchild != NULL)
{
RemoveDoubleChildNode(pDelNode);
}
//第二种情况
else
{
RemoveSingleChildNode(pDelNode);
}
//释放删除节点的内存
delete pDelNode;
pDelNode = NULL;
--mSize;
}
//第一种情况,如果删除的结点是叶子节点
template<class T>
void BinarySearchTree<T>::RemoveNoChildNode(BinaryNode<T>* delNode)
{
BinaryNode<T>* pDelNode = delNode;
if (NULL == pDelNode)
{
return;
}
//判断删除的结点是否是根节点
if (pDelNode == pRoot)
{
pRoot = NULL;
}
else
{
if (pDelNode->pParent->pLchild == pDelNode)
{
pDelNode->pParent->pLchild = NULL;
}
else
{
pDelNode->pParent->pRchild = NULL;
}
}
}
//第二种情况,如果删除的结点只有一个孩子
template<class T>
void BinarySearchTree<T>::RemoveSingleChildNode(BinaryNode<T>* delNode)
{
BinaryNode<T>* pDelNode = delNode;
if (NULL == pDelNode)
{
return;
}
if (pRoot == pDelNode)
{
//拿到删除节点的子节点
BinaryNode<T>* pChild = (pRoot->pLchild == NULL ? pRoot->pRchild : pRoot->pLchild);
//设置子节点的父节点为NULL
pChild->pParent = NULL;
//pRoot指向子节点
pRoot = pChild;
}
else
{
BinaryNode<T>* pChild = (pDelNode->pLchild == NULL ? pDelNode->pRchild : pDelNode->pLchild);
//更新pChild的父节点
pChild->pParent = pDelNode->pParent;
if (pDelNode->pParent->pLchild == pDelNode)
{
pDelNode->pParent->pLchild = pChild;
}
else
{
pDelNode->pParent->pRchild = pChild;
}
}
}
//第三种情况,如果删除的结点有两个孩子
template<class T>
void BinarySearchTree<T>::RemoveDoubleChildNode(BinaryNode<T>* delNode)
{
BinaryNode<T>* pDelNode = delNode;
if (NULL == pDelNode)
{
return;
}
//删除的结点是根节点的情况
//pDelNode左子树最大值的结点,或者右子树中最小值的结点
//获得删除节点左子树中最大的结点
BinaryNode<T>* pLeftMaxNode = GetMaxNode(pDelNode->pLchild);
if (pDelNode == pRoot)
{
if (pLeftMaxNode == pDelNode->pLchild)
{
pLeftMaxNode->pRchild = pRoot->pRchild;
}
else
{
//最大值的结点的父节点指向最大值结点的左子树
pLeftMaxNode->pParent->pRchild = pLeftMaxNode->pLchild;
if (pLeftMaxNode->pLchild != NULL)
{
pLeftMaxNode->pLchild->pParent = pLeftMaxNode->pParent;
}
//让最大值结点左右指针指向根节点的左右子树
pLeftMaxNode->pLchild = pRoot->pLchild;
pLeftMaxNode->pRchild = pRoot->pRchild;
}
pRoot = pLeftMaxNode;
}
else
{
if (pLeftMaxNode == pDelNode->pLchild)
{
pLeftMaxNode->pRchild = pDelNode->pRchild;
//更新待删除结点的右子树的父节点
pDelNode->pRchild->pParent = pLeftMaxNode;
if (pDelNode->pParent->pLchild == pDelNode)
{
pDelNode->pParent->pLchild = pLeftMaxNode;
}
else
{
pDelNode->pParent->pRchild = pLeftMaxNode;
}
}
else
{
pLeftMaxNode->pParent->pRchild = pLeftMaxNode->pLchild;
if (pLeftMaxNode->pLchild != NULL)
{
pLeftMaxNode->pLchild->pParent = pLeftMaxNode->pParent;
}
pLeftMaxNode->pLchild = pDelNode->pLchild;
pLeftMaxNode->pRchild = pDelNode->pRchild;
if (pDelNode->pParent->pLchild == pDelNode)
{
pDelNode->pParent->pLchild = pLeftMaxNode;
}
else
{
pDelNode->pParent->pRchild = pLeftMaxNode;
}
}
}
}

冀公网安备13050302001966号