AVL二叉平衡树的算法

/*二叉平衡树的算法(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");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值