#include<bits/stdc++.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof a)
#define INF 3f3f3f3f
using namespace std;
typedef long long ll;
// 平衡二叉树结点
template <typename T>
struct AvlNode
{
T data;
int height; // 结点所在高度
AvlNode<T> *left;
AvlNode<T> *right;
AvlNode<T>(const T theData):data(theData),left(NULL),right(NULL),height(0){}
};
// AvlTree
template <typename T>
class AvlTree
{
public:
AvlNode<T> *root;
AvlTree<T>():root(NULL){}
~AvlTree<T>(){}
void Insert(AvlNode<T> *&t,T x); // 插入结点
bool Delete(AvlNode<T> *&t,T x); // 删除结点
bool Contains(AvlNode<T> *t,const T x) const; // 查找是否存在给定值的结点
void InorderTraversal(AvlNode<T> *t); // 中序遍历
void PreorderTraversal(AvlNode<T> *t); // 前序遍历
AvlNode<T> *FindMin(AvlNode<T> *t) const; // 最小值结点
AvlNode<T> *FindMax(AvlNode<T> *t) const; // 最大值结点
private:
int GetHeight(AvlNode<T> *t); // 求树的高度
AvlNode<T> *LL(AvlNode<T> *t); // 单旋转 左
AvlNode<T> *RR(AvlNode<T> *t); // 单旋转 右
AvlNode<T> *LR(AvlNode<T> *t); // 双旋转 右左
AvlNode<T> *RL(AvlNode<T> *t); // 双旋转 左右
};
// 查找最大结点
template <typename T>
AvlNode<T> *AvlTree<T>::FindMax(AvlNode<T> *t) const
{
if(t==NULL)
return NULL;
if(t->right==NULL)
return t;
return FindMax(t->right);
}
// 查找最小结点
template <typename T>
AvlNode<T> *AvlTree<T>::FindMin(AvlNode<T> *t) const
{
if(t==NULL)
return NULL;
if(t->left==NULL)
return t;
return FindMin(t->left);
}
// 获取高度
template <typename T>
int AvlTree<T>::GetHeight(AvlNode<T> *t)
{
if(t==NULL)
return -1;
return t->height;
}
// 单旋转
// 左左插入导致不平衡
template <typename T>
AvlNode<T> *AvlTree<T>::LL(AvlNode<T> *t)
{
AvlNode<T> *q=t->left;
t->left=q->right;
q->right=t;
t->height=max(GetHeight(t->left),GetHeight(t->right))+1;
q->height=max(GetHeight(q->left),GetHeight(q->right))+1;
// 注意1:并不是没有连结操作,因为 q 是一个新的 AvlNode<T>,所以在这里返回的时候就连结上这个新修改好的地址
// 注意2:因为地址改变了,它儿子结点原来连的旧地址被更新后会不会断了?不会,因为上面在操作这个更新了
// 注意3:因为地址改变了,新的根结点 q 如何连结原来它的父亲结点?把以上整个更新完后的最新根节点 q,把它们看为一个整体(结点~相当于叶子结点),返回的时候就在做这个覆盖旧的根 t 结点的地址
// 注意4:如果注意2、3还没明白的话看:本博客【基础知识 - 指针篇 - 案例二】
return q;
}
// 单旋转
// 右右插入导致不平衡
template <typename T>
AvlNode<T> *AvlTree<T>::RR(AvlNode<T> *t)
{
AvlNode<T> *q=t->right;
t->right=q->left;
q->left=t;
t->height=max(GetHeight(t->left),GetHeight(t->right))+1;
q->height=max(GetHeight(q->left),GetHeight(q->right))+1;
return q;
}
// 双旋转
// 插入点位于 t 的左儿子的右子树
template <typename T>
AvlNode<T> *AvlTree<T>::LR(AvlNode<T> *t)
{
// 双旋转可以通过两次单旋转实现
// 对 t 的左结点进行RR旋转,再对根节点进行LL旋转
// 记忆法:LR --> RR+LL // 先RR再LL,类似Stack - FILO
RR(t->left);
return LL(t);
}
// 双旋转
// 插入点位于 t 的右儿子的左子树
template <typename T>
AvlNode<T> *AvlTree<T>::RL(AvlNode<T> *t)
{
LL(t->right);
return RR(t);
}
// 插入
template <typename T>
void AvlTree<T>::Insert(AvlNode<T> *&t,T x)
{
if(t==NULL)
{
t=new AvlNode<T>(x); // 新生成的自动连结父亲
}
else if(x<t->data)
{
Insert(t->left,x);
// 判断平衡情况
if(GetHeight(t->left)-GetHeight(t->right)>1)
{
// 分两种情况:左左 or 左右
if(x<t->left->data) // 左左
t=LL(t);
else // 左右
t=LR(t);
}
}
else if(x>t->data)
{
Insert(t->right,x);
if(GetHeight(t->right)-GetHeight(t->left)>1)
{
if(x>t->right->data)
t=RR(t);
else
t=RL(t);
}
}
else
; // 数据重复,看情况处理
// 不能把以下此代码移动到 t==NULL 里,因为其他 (else if)'s t 还需要更新
t->height=max(GetHeight(t->left),GetHeight(t->right))+1;
}
// 删除
template <typename T>
bool AvlTree<T>::Delete(AvlNode<T> *&t,T x)
{
// t 为空,未找到要删除的结点
if(t==NULL)
return false;
// 找到要删除的结点
else if(t->data==x)
{
// 左右子树都非空
if(t->left!=NULL && t->right!=NULL)
{
// 在高度更大的那个子树上进行删除操作
// 左子树高度更大,则删除左子树中data最大的结点,将其赋给根节点
if(GetHeight(t->left)>GetHeight(t->right))
{
t->data=FindMax(t->left)->data;
Delete(t->left,t->data);
}
else // 右子树高度更大,则删除右子树中data最小的结点,将其赋给根节点
{
t->data=FindMin(t->right)->data;
Delete(t->right,t->data);
}
}
else
{
// 左右子树右一个不为空(或左右子树都为空),直接用需要删除的结点的子结点替换即可
AvlNode<T> *old=t;
// 当左右子树右一个不为空,则 t 赋值为不空的子结点
// 当左右子树都为空,则随意
t=t->left?t->left:t->right;
delete old;
}
}
// 要删除的结点在左子树上
else if(x<t->data)
{
// 递归删除左子树上的结点
Delete(t->left,x);
// 判断是否仍然满足平衡条件
if(GetHeight(t->right)-GetHeight(t->left)>1)
{
if(GetHeight(t->right->left)>GetHeight(t->right->right))
{
t=RL(t);
}
else
{
t=RR(t);
}
}
else // 满足平衡条件,调整高度信息
{
t->height=max(GetHeight(t->left),GetHeight(t->right))+1;
}
}
// 要删除的结点在右子树上
else
{
Delete(t->right,x);
if(GetHeight(t->left)-GetHeight(t->right)>1)
{
if(GetHeight(t->left->right)>GetHeight(t->left->left))
{
t=LR(t);
}
else
{
t=LL(t);
}
}
else // 满足平衡条件,调整高度信息
{
t->height=max(GetHeight(t->left),GetHeight(t->right))+1;
}
}
return true;
}
// 查找结点
template <typename T>
bool AvlTree<T>::Contains(AvlNode<T> *t,const T x) const
{
if(t==NULL)
return false;
if(x<t->data)
return Contains(t->left,x);
else if(x>t->data)
return Contains(t->right,x);
else
return true;
}
// 中序遍历
template <typename T>
void AvlTree<T>::InorderTraversal(AvlNode<T> *t)
{
if(t)
{
InorderTraversal(t->left);
printf("%d ",t->data);
InorderTraversal(t->right);
}
}
// 前序遍历
template <typename T>
void AvlTree<T>::PreorderTraversal(AvlNode<T> *t)
{
if(t)
{
printf("%d ",t->data);
PreorderTraversal(t->left);
PreorderTraversal(t->right);
}
}
// 显示中序+前序遍历结果
template <typename T>
void showTraversal(AvlTree<T> &tree)
{
printf("中序遍历:");
tree.InorderTraversal(tree.root);
printf("\n前序遍历:");
tree.PreorderTraversal(tree.root);
}
// 测试数据:18 14 20 12 16 1 -1
int main()
{
AvlTree<int> tree;
int val,tmp;
printf("请输入整数建立二叉树(-1 end):\n");
while(~scanf("%d",&val))
{
if(val==-1)
break;
tree.Insert(tree.root,val);
}
showTraversal(tree);
printf("\n请输入要查找的结点: ");
scanf("%d",&tmp);
if(tree.Contains(tree.root,tmp))
printf("已找到\n");
else
printf("不存在\n");
printf("请输入要删除的结点: ");
scanf("%d",&tmp);
tree.Delete(tree.root,tmp);
showTraversal(tree);
return 0;
}