二叉平衡搜索树
相关概念
引入原因
在使用二叉搜索树的时候,有时该树会退化为链表,这样就会使遍历二叉树的时间复杂度退化到O(n),使的搜索树的效率降低。因此为了保障树的效率,我们要设法使其一直保持在平衡的最优状态。
平衡的概念
一个根节点的左右子树高度相差不超过2,在此基础上需要一个用来判断的平衡因子。因此我们需要记录在每个节点处树的高度。通过比较他左右子树的高度来判断在该节点处是否需要进行调整
调整操作
LL型
根节点的下一个节点无右子树
根节点的下一个节点有右子树
AVLTree* llRotation(AVLTree *T)//得到根节点
{
AVLTree *temp=T->left;//得到中间节点
T->left=temp->right;//假如中间节点有右孩子,就让中间节点的右孩子成为根节点的左孩子,若中间节点没右孩子就令其指向空
temp->right=T;//让根节点作为中间节点的右节点
temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;//分别得到调整之后中间节与根的树高
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
return temp;//调整后中间节点变为根节点
}
RR型
与LL型恰好相反
AVLTree* rrRotation(AVLTree *T)//得到根节点以及指向根节点的指针
{
AVLTree *temp=T->right;//得到中间节点
T->right=temp->left;//假如中间节点有左孩子,就让中间节点的左孩子成为根节点的右孩子,若中间节点没孩子就令其指向空
temp->left=T;//让根节点作为中间节点的左节点
temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;//分别得到调整之后中间节与根的树高
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
return temp;//调整后中间节点变为根节点
}
LR型
LR型相当于先对中间节点的子树进行RR型调整再对调整完后根节点的子树进行LL型调整
RL型
与LR型相反,先对中间节点的子树进行LL型调整再对调整完后根节点的子树进行RR型调整
整体调整代码
AVLTree* fixed(AVLTree *T,int data)
{
if(GET_HEIGHT(T->left)-GET_HEIGHT(T->right)==2){
if(T->left->data > data){
T=llRotation(T);
}else{
T->left=rrRotation(T->left);
T=llRotation(T);
}
}else if(GET_HEIGHT(T->right)-GET_HEIGHT(T->left)==2){
if(T->right->data < data){
T=rrRotation(T);
}else{
T->right=llRotation(T->right);
T=rrRotation(T);
}
}
return T;
}
完整代码实现
整体的思路
在插入与删除中,均为先对带处理的节点进行插入或删除,再通过回溯的方式找到导致树不平衡的根节点,从小到大将树修正
#include <stdio.h>
#include <stdlib.h>
#define MAX(a, b) (a > b ? a : b)//比较得出左右两颗子树中更高的一颗子树
#define GET_HEIGHT(T) (T ? T->hight:0)//得到树的高度
typedef struct TreeNode
{
int data,hight;
struct TreeNode * left;
struct TreeNode * right;
}AVLTree;
AVLTree * getnewnode(int data)//初始化树的节点
{
AVLTree *T = NULL;
T = (AVLTree *)malloc(sizeof(AVLTree *));
T->data = data;
T->hight=0;
T->right = NULL;
T->left = NULL;
return T;
}
AVLTree* rrRotation(AVLTree *T)//得到根节点以及指向根节点的指针
{
AVLTree *temp=T->right;//得到中间节点
T->right=temp->left;//假如中间节点有左孩子,就让中间节点的左孩子成为根节点的右孩子
temp->left=T;//让根节点作为中间节点的左节点
temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;//分别得到调整之后中间节与根的树高
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
return temp;//调整后中间节点变为根节点
}
AVLTree* llRotation(AVLTree *T)
{
AVLTree *temp=T->left;
T->left=temp->right;
temp->right=T;
temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
return temp;
}
AVLTree* fixed(AVLTree *T,int data)
{
if(GET_HEIGHT(T->left)-GET_HEIGHT(T->right)==2){//若左树比右树高大于2
if(T->left->data > data){//如果中间节点的值大于导致不平衡节点的值,则为ll调整
T=llRotation(T);
}else{//否则为lr调整
T->left=rrRotation(T->left);
T=llRotation(T);
}
}else if(GET_HEIGHT(T->right)-GET_HEIGHT(T->left)==2){//若右树比左树的高大于2
if(T->right->data < data){//如果中间节点的值小于导致不平衡节点的值,则为rr调整
T=rrRotation(T);
}else{//否则为rl调整
T->right=llRotation(T->right);
T=rrRotation(T);
}
}
return T;
}
AVLTree* insertTree(AVLTree *T, int data)
{
if (T == NULL){
T=getnewnode(data);
printf("%d插入树中\n",data);
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;//更新当前节点的树高
return T;
}
if (T->data > data){
T->left = insertTree(T->left, data);
T=fixed(T,data);
}else{
if(T->data < data){
T->right = insertTree(T->right, data);
T=fixed(T,data);
}else{
printf("%d已在树中,不能再次插入!!!\n",data);
}
}
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;//更新当前节点的树高
return T;
}
//删除节点
AVLTree* findMax2(AVLTree* T)
{
AVLTree* p=T;
while(p->right!=NULL){
p=p->right;
}
return p;
}
AVLTree* Delete(AVLTree * T,int data)
{
if(T==NULL) return T;
else if(data<T->data) T->left = Delete(T->left,data);
else if(data>T->data) T->right = Delete(T->right,data);
else{
if(T->left==NULL&&T->right==NULL){
free(T);
T=NULL;
}
else if(T->right==NULL){
AVLTree *temp=T;
T=T->left;
free(temp);
}
else if(T->left==NULL){
AVLTree *temp=T;
T=T->right;
free(temp);
}
else{
AVLTree *temp=findMax2(T->left);
T->data=temp->data;
T->left=Delete(T->left,temp->data);
}
}
if(T){
T=fixed(T,data);
T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
}
return T;
}
void Preorder(AVLTree * T)//前序遍历打印验证结果
{
if(T==NULL){
return;
}
printf("%d ",T->data);
Preorder(T->left);
Preorder(T->right);
}
int main()
{
int i;
int a[9]={1,2,3,4,5,6,7,8,9};
AVLTree *T=NULL;
for(i=0;i<9;i++){
T=insertTree(T,a[i]);
}
Preorder(T);
Delete(T,5);
printf("\n");
Preorder(T);
}