在创建树的时候保持平衡二叉树性质,即每插入一个新节点都要做平衡处理,假如插入节点后,二叉树没有失去平衡,则不做处理,否则,根据不同情况做不同处理。
当平衡的二叉排序树因插入节点而失去平衡时,仅需对最小不平衡子树进行平衡旋转处理即可。因为经过旋转处理之后的子树深度和插入之前相同,因而不影响插入路径上所有祖父节点的平衡点。
一般情况下,假设由于在二叉排序树上插入节点而失去平衡的最小子树根节点的指针为a(即a是离插入节点最近,且平衡因子绝对值超过1的祖先节点),则失去平衡后进行调整的规律可归纳为下列4中情况:
(1)、单向右旋平衡处理:由于*a的左子树根节点*b(假设*b的右节点为*c)的左子树上插入节点,*a的平衡因子由1增到2,致使以*a为根的子树失去平衡,则需进行一次向右的顺时针旋转操作。指针调整情况是:*a的左指针*c,*b的右指针指向*a,若*a的父节点存在,*a的父节点的左或右(根据*a以前其父节点的左孩子还是右孩子)指针指向*b。
(2)、单向左旋平衡处理:由于在*a的右子树根节点*b(假设*b的左节点为*c)的右子树上插入节点,*a平衡因子由-1变为-2,致使以*a为根节点的子树失去平衡,则需进行一次向左的逆时针旋转操作。指针调整情况是:*a的右指针指向*c,*b的左指针指向*a,若*a的父节点存在,*a的父节点的左或右(根据*a以前其父节点的左孩子还是右孩子)指针指向*b。
(3)、双向旋转(先左后右)平衡处理:由于在*a的左子树根节点*b(假设*b的右节点是*c,*c的左节点是*d,*c的右节点是*e)的右子树上插入节点,*a的平衡因子由1增至2,致使以*a为根节点的子树失去平衡,则需进行两次旋转(先左旋,后右旋)操作。指针调整情况是:*c的左指针指向*b,*c的右指针指向*a,*b的右指针指向*d,*a的左指针指向*e,若*a的父节点存在,*a的父节点的左或右(根据*a以前其父节点的左孩子还是右孩子)指针指向*c。
(4)、双向旋转(先右后左)平衡处理:由于*a的右子树根节点*b(假设*b的左节点是*c,*c的左节点是*d,*c的右节点是*e)的左子树插入节点,*a平衡因子由-1变为-2,致使以*a为根节点的子树失去平衡,则需要进行两次旋转(先右后左)操作。指针调整情况是:*c的左指针指向*a,*c的右指针指向*b,*b的左指针指向*e,*a的右指针指向*d,若*a的父节点存在,*a的父节点的左或右(根据*a以前其父节点的左孩子还是右孩子)指针指向*c。
以下代码可作为参考:
#include<stdio.h>
#include<stdlib.h>
typedef struct bi_search_tree //表示二叉树节点的数据结构
{
int value;
struct bi_search_tree* left;
struct bi_search_tree* right;
}bi_search_tree;
typedef struct pointer_link //查找插入位置时用的链表节点结构
{
bi_search_tree* which; //指向二叉树节点的指针
struct pointer_link* parent; //指向下一个链表节点
}pointer_link;
void output_tree(bi_search_tree* root) //用递归方法,输出二叉树中各节点以及其左右孩子的值
{
if(root!=NULL)
{
printf("iam=%d ",root->value);
if(root->left!=NULL)
printf("left=%d ",root->left->value);
if(root->right!=NULL)
printf("right=%d ",root->right->value);
printf("\n");
output_tree(root->left);
output_tree(root->right);
}
}
int main()
{
void insert(bi_search_tree**,int);
void free_tree_space(bi_search_tree*);
int i,n,value;
printf("input how many numbers you need to create the tree\n");
scanf("%d",&n);
bi_search_tree* root=NULL;
for(i=0;i<n;i++)
{
scanf("%d",&value);
insert(&root,value);
}
output_tree(root);
if(root!=NULL)
free_tree_space(root);
return 0;
}
void free_tree_space(bi_search_tree* root) //用递归方法释放二叉树所占用的空间
{
if(root->left!=NULL)
free_tree_space(root->left);
if(root->right!=NULL)
free_tree_space(root->right);
free(root);
}
int depth(bi_search_tree* node) //用递归方法计算以某个节点为根节点的子树的深度
{
if(node==NULL)
return 0;
else
return (depth(node->left)>=depth(node->right))?(depth(node->left)+1):(depth(node->right)+1);
}
int rotate_type(pointer_link* rear,int value,pointer_link** who_debalance)
{
int type=0;
rear=rear->parent;
while(rear!=NULL)
{
int balance_factor=depth(rear->which->left)-depth(rear->which->right);
if(balance_factor==-2) //平衡因子为-2时,可能为RL型,也可能为RR型
{
if(value<rear->which->right->value)
{
type=1;
*who_debalance=rear;
break;
}
else
{
type=2;
*who_debalance=rear;
break;
}
}
if(balance_factor==2) //平衡因子为2时,可能为LL型,也可能为LR型
{
if(value<rear->which->left->value)
{
type=3;
*who_debalance=rear;
break;
}
else
{
type=4;
*who_debalance=rear;
break;
}
}
rear=rear->parent;
}
return type;
}
void insert(bi_search_tree** root_p,int value) //想以**root为根节点的平衡二叉树中插入值value
{
if(*root_p==NULL) //插入之前平衡二叉树没有节点
{
*root_p=(bi_search_tree*)malloc(sizeof(bi_search_tree));
(*root_p)->value=value;
(*root_p)->left=NULL;
(*root_p)->right=NULL;
}
else //插入之前平衡二叉树已经存在,即已经有节点
{
pointer_link* rear=(pointer_link*)malloc(sizeof(pointer_link));
pointer_link* who_losebalance; //指向失去平衡的最小子树的根节点
rear->which=*root_p;
rear->parent=NULL;
while(1) //查找value应该的插入位置,并用链表记录从根节点到插入位置的路径
{
if(value<rear->which->value)
{
if(rear->which->left==NULL)
{
rear->which->left=(bi_search_tree*)malloc(sizeof(bi_search_tree));
rear->which->left->value=value;
rear->which->left->left=NULL;
rear->which->left->right=NULL;
break;
}
else
{
pointer_link* rear_new=(pointer_link*)malloc(sizeof(pointer_link));
rear_new->parent=rear;
rear_new->which=rear->which->left;
rear=rear_new;
}
}
if(value>rear->which->value)
{
if(rear->which->right==NULL)
{
rear->which->right=(bi_search_tree*)malloc(sizeof(bi_search_tree));
rear->which->right->value=value;
rear->which->right->left=NULL;
rear->which->right->right=NULL;
break;
}
else
{
pointer_link* rear_new=(pointer_link*)malloc(sizeof(pointer_link));
rear_new->parent=rear;
rear_new->which=rear->which->right;
rear=rear_new;
}
}
if(value==rear->which->value)
{
printf("this value has already been in the binary search tree\n");
break;
}
}
int type=rotate_type(rear,value,&who_losebalance);
switch (type) //根据失去平衡不同类型(LL、RR,LR,RL)做不同处理
{
case 0: break;
case 1:
{
bi_search_tree* r=who_losebalance->which->right;
bi_search_tree* l=who_losebalance->which->right->left;
bi_search_tree* p;
if(who_losebalance->parent!=NULL)
p=who_losebalance->parent->which;
else
p=NULL;
who_losebalance->which->right=l->left;
r->left=l->right;
l->left=who_losebalance->which;
l->right=r;
if(p!=NULL)
{
if(p->left==who_losebalance->which)
p->left=l;
else
p->right=l;
}
else
*root_p=l;
}
break;
case 2:
{
bi_search_tree* p;
if(who_losebalance->parent!=NULL)
p=who_losebalance->parent->which;
else
p=NULL;
bi_search_tree* r1=who_losebalance->which->right;
bi_search_tree* r2=who_losebalance->which->right->right;
who_losebalance->which->right=r1->left;
r1->left=who_losebalance->which;
if(p!=NULL)
{
if(p->left==who_losebalance->which)
p->left=r1;
else
p->right=r1;
}
else
*root_p=r1;
}
break;
case 3:
{
bi_search_tree* p;
if(who_losebalance->parent!=NULL)
p=who_losebalance->parent->which;
else
p=NULL;
bi_search_tree* l1=who_losebalance->which->left;
bi_search_tree* l2=who_losebalance->which->left->left;
who_losebalance->which->left=l1->right;
l1->right=who_losebalance->which;
if(p!=NULL)
{
if(p->left==who_losebalance->which)
p->left=l1;
else
p->right=l1;
}
else
*root_p=l1;
}
break;
case 4:
{
bi_search_tree* l=who_losebalance->which->left;
bi_search_tree* r=who_losebalance->which->left->right;
bi_search_tree* p;
if(who_losebalance->parent!=NULL)
p=who_losebalance->parent->which;
else
p=NULL;
who_losebalance->which->left=r->right;
l->right=r->left;
r->right=who_losebalance->which;
r->left=l;
if(p!=NULL)
{
if(p->left==who_losebalance->which)
p->left=r;
else
p->right=r;
}
else
*root_p=r;
}
break;
default: printf("Not the one of the types 1,2,3,4\n");
}
while(rear!=NULL)
{
pointer_link* d=rear;
rear=rear->parent;
free(d);
}
}
}