/*二叉平衡树的算法(C语言)
二叉平衡树是一种特殊的二叉搜索树,
其在搜索上的时间复杂度基本上是线性表与二叉树中最小的,
因此是一个非常非常重要的知识点,且应用十分广泛。
本文的算法基于二叉搜索树的插入与删除算法演变而来。
另外构造了3个函数,而这三个函数
BFInitiate(), RightRotation(), LeftRotation()
在本算法中是十分最重要的。
本文采用三重链表,
可以从零开始构造二叉平衡树,
自动旋转保持树的平衡;
又可以删除二叉平衡树的某个节点(包括根节点),
删除后也可以多次自动旋转保持平衡。
注意是多次哦,
因为进行删作,即使进行自动旋转操作后,
有可能还是不平衡,所以还需要再次自动旋转操作。*/
#include<stdio.h>
#include<stdlib.h>
typedef struct btnode {
int key;
int bf;
struct btnode* Lchild, * Rchild, * Father;
}BTNode;
typedef struct btree {
struct btnode* Root;
}BTree;
BTNode* NewNode() {
BTNode* p = (BTNode*)malloc(sizeof(BTNode));
return p;
}
BTNode* NewNode2(int x) {
BTNode* p = (BTNode*)malloc(sizeof(BTNode));
p->key = x;
p->bf = 0;
p->Lchild = NULL;
p->Rchild = NULL;
p->Father = NULL;
return p;
}
void CreateBT(BTree* bt) {
bt->Root = NULL;
}
void MakeBT(BTree* bt, int x, BTree* lt, BTree* rt) {
BTNode* p = NewNode();
p->key = x;
p->Father = NULL;
if (rt->Root != NULL) {
rt->Root->Father = p;
}
p->Rchild = rt->Root;
if (lt->Root != NULL) {
lt->Root->Father = p;
}
p->Lchild = lt->Root;
lt->Root = rt->Root = NULL;
bt->Root = p;
}
void BreakBT(BTree* bt, BTree* lt, BTree* rt) {
BTNode* p = bt->Root;
if (p) {
lt->Root = p->Lchild;
rt->Root = p->Rchild;
bt->Root = NULL;
free(p);
}
}
int Size(BTNode* p) {
int s, s1, s2;
if (!p) {
return 0;
}
else {
s1 = Size(p->Lchild);
s2 = Size(p->Rchild);
s = s1 + s2 + 1;
return s;
}
}
int SizeofBT(BTree bt) {
return Size(bt.Root);
}
int Depth(BTNode* p) {
if (!p) {
return 0;
}
else {
return 1 + max(Depth(p->Lchild), Depth(p->Rchild));
}
}
int DepthofBT(BTree bt) {
return Depth(bt.Root);
}
int CountLeaf(BTNode* p, int count)
{
if (p != NULL)
{
if (p->Lchild == NULL && p->Rchild == NULL) {
count++;
}
count = CountLeaf(p->Lchild, count);
count = CountLeaf(p->Rchild, count);
}
return count;
}
int NumberofLeaf(BTree bt, int count) {
return CountLeaf(bt.Root, count);
}
void LevelOrd(BTree bt) {
BTNode* p;
BTNode* queue[256];
int front = -1, rear = -1;
if (bt.Root == NULL) {
return;
}
p = bt.Root;
rear++;
queue[rear] = p;
while (front != rear) {
front++;
p = queue[front];
printf("%d_[%d] ", p->key, p->bf);
if (p->Lchild != NULL) {
rear++;
queue[rear] = p->Lchild;
}
if (p->Rchild != NULL) {
rear++;
queue[rear] = p->Rchild;
}
}
printf("\n");
}
//重新初始化树中结点的一个个balance值,和按层次遍历树的结点的算法相同,每遍历到一个结点,就会重新计算该节点的balance值
void BFInitiate(BTree bt) {
BTNode* p;
BTNode* queue[256];
int front = -1, rear = -1;
p = bt.Root;
if (bt.Root == NULL) return;
rear++;
queue[rear] = p;
while (front != rear) {
front++;
p = queue[front];
p->bf = Depth(p->Lchild) - Depth(p->Rchild);
if (p->Lchild != NULL) {
rear++;
queue[rear] = p->Lchild;
}
if (p->Rchild != NULL) {
rear++;
queue[rear] = p->Rchild;
}
}
printf("\n");
}
//左旋转函数
void LeftRotation(BTNode* s, BTree* bt) {
BTNode* r, * u;
r = (BTNode*)malloc(sizeof(BTNode));
u = (BTNode*)malloc(sizeof(BTNode));
r = s->Lchild;
if (r->bf == -1) {//执行LR旋转
u = r->Rchild;
r->Rchild = u->Lchild;
if (u->Lchild != NULL) {
u->Lchild->Father = r;
}
u->Lchild = r;
s->Lchild = u->Rchild;
if (u->Rchild != NULL) {
u->Rchild->Father = s;
}
u->Rchild = s;
if (s->Father != NULL) {
if (s->Father->Lchild == s) {
s->Father->Lchild = u;
}
if (s->Father->Rchild == s) {
s->Father->Rchild = u;
}
u->Father = s->Father;//把s的父节点赋给u的父指针指向的结点
s->Father = u;
r->Father = u;
}
else {
u->Father = NULL;
bt->Root = u;
r->Father = u;
s->Father = u;
}
}
else {//执行LL旋转,
s->Lchild = r->Rchild;
if (r->Rchild != NULL) {
r->Rchild->Father = s;
}
r->Rchild = s;
if (s->Father != NULL) {
if (s->Father->Rchild == s) {
s->Father->Rchild = r;
}
if (s->Father->Lchild == s) {
s->Father->Lchild = r;
}
r->Father = s->Father;
s->Father = r;
}
else {
r->Father = NULL;
bt->Root = r;
s->Father = r;
}
}
}
//右旋转函数
void RightRotation(BTNode* s, BTree* bt) {
BTNode* r, * u;
r = (BTNode*)malloc(sizeof(BTNode));
u = (BTNode*)malloc(sizeof(BTNode));
r = s->Rchild;
if (r->bf == 1) {//执行RL旋转
u = r->Lchild;
r->Lchild = u->Rchild;
if (u->Rchild != NULL) {
u->Rchild->Father = r;
}
u->Rchild = r;
s->Rchild = u->Lchild;
if (u->Lchild != NULL) {
u->Lchild->Father = s;
}
u->Lchild = s;
if (s->Father != NULL) {
if (s->Father->Lchild == s) {
s->Father->Lchild = u;
}
if (s->Father->Rchild == s) {
s->Father->Rchild = u;
}
u->Father = s->Father;
s->Father = u;
r->Father = u;
}
else {
u->Father = NULL;
bt->Root = u;
r->Father = u;
s->Father = u;
}
}
else {//执行RR旋转
s->Rchild = r->Lchild;
if (r->Lchild != NULL) {
r->Lchild->Father = s;
}
r->Lchild = s;
if (s->Father != NULL) {
if (s->Father->Rchild == s) {
s->Father->Rchild = r;
}
if (s->Father->Lchild == s) {
s->Father->Lchild = r;
}
r->Father = s->Father;
s->Father = r;
}
else {
r->Father = NULL;
bt->Root = r;
s->Father = r;
}
}
}
//二叉平衡树的插入运算
void AVListInsert(BTree* bt, int k) {
BTNode* q, * p, * s;
s = (BTNode*)malloc(sizeof(BTNode));
p = bt->Root;
s = p;
while (p) {
s = p;
if (k < p->key) {
p = p->Lchild;
}
else if (k > p->key) {
p = p->Rchild;
}
else {
printf("Duplication! \n");
return;
}
}
//这里调用二叉搜索树的迭代算法,找到要插入的位置。
//s指代插入的点的父节点,p如果不重复的话,到最后应该为null了。
q = NewNode2(k);
if (bt->Root) {//判断是不是头一次创建结点
if (k < s->key) {
s->Lchild = q;
q->Father = s;
}
if (k > s->key) {
s->Rchild = q;
q->Father = s;
}
}
else {
bt->Root = q;
return;//如果是的话,将新创建的q结点作为根节点。然后直接返回,退出该函数
}
while (1) {
s->bf = Depth(s->Lchild) - Depth(s->Rchild);//插入q后,向上依次更新其父节点的balance。
if (s->bf < -1 || s->bf>1) {//遇到的第一个更新完balance后不再平衡的父节点,就跳出循环,执行旋转操作,
break;
}
if (s->Father == NULL) {//如果最后到达最顶层,则也跳出循环
break;
}
s = s->Father;
}
if (s->Father == NULL && s->bf >= -1 && s->bf <= 1) {
printf("\n二叉树已经平衡,无需再平衡!\n");
}
if (s->bf == 2) {//如果s的balance为2,代表左子树比较庞大,需要执行左旋转
LeftRotation(s, bt);
}
if (s->bf == -2) {//如果s的balance为-2,代表右子树比较庞大,需要执行右旋转
RightRotation(s, bt);
}
}
void Visit(BTNode* p) {
printf("%d_[%d] ", p->key, p->bf);
}
void PreOrd(void (*Visit)(BTNode* u), BTNode* t) {
if (t) {
(*Visit)(t);
PreOrd(Visit, t->Lchild);
PreOrd(Visit, t->Rchild);
}
}
void InOrd(void (*Visit)(BTNode* u), BTNode* t) {
if (t) {
InOrd(Visit, t->Lchild);
(*Visit)(t);
InOrd(Visit, t->Rchild);
}
}
void PostOrd(void (*Visit)(BTNode* u), BTNode* t) {
if (t) {
PostOrd(Visit, t->Lchild);
PostOrd(Visit, t->Rchild);
(*Visit)(t);
}
}
void PreOrder(BTree* bt, void (*Visit)(BTNode* u)) {
PreOrd(Visit, bt->Root);
}
void InOrder(BTree* bt, void (*Visit)(BTNode* u)) {
InOrd(Visit, bt->Root);
}
void PostOrder(BTree* bt, void (*Visit)(BTNode* u)) {
PostOrd(Visit, bt->Root);
}
//二叉平衡时的删除运算
void AVLremove(BTree* bt, int k) {
BTNode* c, * r, * s, * p, * q;
q = (BTNode*)malloc(sizeof(BTNode));
p = bt->Root;
while (p && p->key != k) {
q = p;
if (k < p->key) {
p = p->Lchild;
}
else {
p = p->Rchild;
}
}//调用二叉搜索树的搜索算法,是否能找到该要删除的节点
if (!p) {
printf("\nNo Element with Key k!\n");
return;
}
printf("\nfind the elememt which you want to delete: %d\n", p->key);
if (p->Lchild && p->Rchild) {//看下要删除的结点是否有两个孩子,如果有,就找到该节点的中序遍历次序下的后继结点
s = p->Rchild;
r = p;
while (s->Lchild) {
r = s;
s = s->Lchild;
}
p->key = s->key;//将该节点中序遍历次序下的后继结点的值赋给该节点。
p = s;//然后,刷新p,q,新的p就是原来要删除的节点的中序遍历次序下的后继结点,q就是原来要删除的结点的中序遍历次序下后继的结点的父节点
q = r;
}
if (p->Lchild) {//这一段代码应该基本上泡不到,是个小bug,因为现在的p已经不可能有左孩子了。
c = p->Lchild;
}
else {
c = p->Rchild;//把新节点p的右孩子提出来
}
if (p == bt->Root) {
bt->Root = c;
}
else if (p == q->Lchild) {
q->Lchild = c;
if (c != NULL) {
c->Father = q;
}
}
else {
q->Rchild = c;
if (c != NULL) {
c->Father = q;
}
}
free(p);//在这里执行删除操作
printf("Remove Succeeded!\n");
if (bt->Root != NULL) {
BFInitiate(*bt);
}
else {
return;//如果删的是只有一个父节点的AVL树,就会在这里直接跳出函数
}
printf("%d\n", q->bf);
LABEL:
while (1) {
q->bf = Depth(q->Lchild) - Depth(q->Rchild);
if (q->bf < -1 || q->bf>1) {
break;
}
if (q->Father == NULL) {
break;
}
q = q->Father;
}
if (q->Father == NULL && q->bf >= -1 && q->bf <= 1) {
printf("\n二叉树已经平衡,无需再平衡!\n");
}
if (q->bf == 2) {
LeftRotation(q, bt);
BFInitiate(*bt);
goto LABEL;
//实时证明,旋转完一次以后,有可能还是无法平衡,所以还需要再次进行判断是否是平衡了,就需要引入一个循环。如果不平衡,需要再次旋转,直到平衡为止
}
if (q->bf == -2) {
RightRotation(q, bt);
BFInitiate(*bt);
goto LABEL;
//实时证明,旋转完一次以后,有可能还是无法平衡,所以还需要再次进行判断是否是平衡了,就需要引入一个循环。如果不平衡,需要再次旋转,直到平衡为止
}
}
void main() {
BTree* z;
z = (BTree*)malloc(sizeof(BTree));
CreateBT(z);
AVListInsert(z, 100); //从无到有构造二叉平衡树时,根节点一定要最先创建!
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 50);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 200);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 150);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 400);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 800);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 125);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 110);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 105);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 170);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 120);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVListInsert(z, 106);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVLremove(z, 150);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
AVLremove(z, 120);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
AVLremove(z, 170);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
AVLremove(z, 100);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
AVListInsert(z, 120);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
AVLremove(z, 105);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
AVLremove(z, 50);
BFInitiate(*z);
LevelOrd(*z);
InOrder(z, Visit);
printf("\n");
printf("\n");
}
AVL二叉平衡树的算法
最新推荐文章于 2022-07-24 13:28:39 发布