本题考场avl树的四种旋转方法与树的深度的计算

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

首先题目告诉了四种AVL的自平衡方法,figure1到figure4分别是LL旋转,RR旋转,RL旋转与LR旋转,这是AVL树的自平衡法则

Root of AVL Tree
Root of AVL Tree
Root of AVL Tree
Root of AVL Tree

Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the root of the resulting AVL tree in one line.

Sample Input 1:

5
88 70 61 96 120

Sample Output 1:

70

Sample Input 2:

7
88 70 61 96 120 90 65

Sample Output 2:

88

思路:

在程序最开始,我们需要定义树的结构体:

typedef struct Treenode * Tree;
struct Treenode
{
	int v;//储存节点的值
	Tree left, right;//储存左树的位置与右树的位置
};

主程序尽量简单:

int main()
{
	int n;
	scanf("%d", &n);
	Tree T;
	T = maketree(n);//构建AVL树
	printf("%d\n",T->v);//输出该树的根节点
	return 0;
}

构建一颗AVL树的函数有以下几个:

Tree maketree(int n);//建立自平衡二叉树
Tree newnode(int v);//建立新节点
Tree insert(Tree T, int v);//向树中插入元素
int height(Tree T);//计算一个树的高度
Tree LLrotation(Tree T);//LL旋转,左单旋转
Tree LRrotation(Tree T);//LR旋转,左右双旋
Tree RRrotation(Tree T);//RR旋转,右单旋转
Tree RLrotation(Tree T);//RL旋转,右左双旋

其中建立树的函数时会调用两个函数:建立新节点函数与插入新元素函数,其中插入新元素的函数会调用建立新节点函数与递归调用自身,同时插入完节点后,需要根据高度函数计算该树目前是否自平衡,不平衡的话需要根据四种情况进行调整,建立树的函数如下:

Tree maketree(int n)
{
	int v;
	scanf("%d", &v);
	Tree T = newnode(v);//建立根节点
	for (int i = 1; i < n; i++)
	{
		scanf("%d", &v);
		T = insert(T,v);//首先插入形成新的二叉树;
	}
	return T;
}

Tree newnode(int v)
{
	Tree T = (Tree)malloc(sizeof(struct Treenode));
	T->v = v;
	T->left = T->right = NULL;
	//T->height = 1;
	return T;
}

Tree insert(Tree T, int v)
{
	if (!T) T = newnode(v);
	else
	{
		if (v < T->v )
		{
			T->left = insert(T->left, v);
			if (height(T->left) - height(T->right) == 2)//如果插入后左边的树高度达到2
			{
				if (v < T->left->v)//LL旋转
					T = LLrotation(T);
				else//LR旋转
					T = LRrotation(T);
			}
		}
		else
		{
			T->right = insert(T->right, v);
			if (height(T->right) - height(T->left) == 2)//如果插入后右边的树高度达到2
			{
				if (v < T->right->v)//RL旋转
					T = RLrotation(T);
				else//RR旋转
					T = RRrotation(T);
			}
		}
	}
	return T;
}

int height(Tree T)
{
	int hl, hr, max;
	if (T)
	{
		hl = height(T->left);
		hr = height(T->right);
		max = hl > hr ? hl : hr;
		return max + 1;
	}
	else
		return 1;
}

根据题目的提示,我们需要对四种旋转的方式定义四个函数

LL旋转:
Root of AVL Tree
方法如上,代码如下:

Tree LLrotation(Tree T)
{
	Tree a = T, b = T->left;//记录原来根节点,根节点的左节点
	Tree bl=b->left, br=b->right, ar=a->right;//记录三个需要旋转的树
	a->left = br;
	a->right = ar;
	b->left = bl;
	b->right = a;
	return b;
}

LR旋转:
Root of AVL Tree
方法如上,代码如下:

Tree LRrotation(Tree T)
{
	Tree a = T, b = T->left,c = b->right;//记录原来根节点,根节点的左节点,左节点的右节点
	Tree bl = b->left, cl = c->left, cr=c->right,ar = a->right;//记录四个需要旋转的树
	b->left = bl;
	b->right = cl;
	a->left = cr;
	a->right = ar;
	c->left = b;
	c->right = a;
	return c;
}

RR旋转:
Root of AVL Tree
方法如上,代码如下:

Tree RRrotation(Tree T)
{
	Tree a = T, b = T->right;//记录原来根节点,根节点的右节点
	Tree al = a->left, bl = b->left, br = b->right;//记录三个需要旋转的树
	a->left = al;
	a->right = bl;
	b->left = a;
	b->right = br;
	return b;
}

RL旋转:
Root of AVL Tree
方法如上,代码如下:

Tree RLrotation(Tree T)
{
	Tree a = T, b = T->right, c = b->left;//记录原来根节点,根节点的右节点,右节点的左节点
	Tree al=a->left,br=b->right,cl=c->left,cr=c->right;//记录四个需要旋转的树
	a->left = al;
	a->right = cl;
	b->left = cr;
	b->right = br;
	c->left = a;
	c->right = b;
	return c;
}

以上就完成了一个AVL树的建立

源代码:

#include<stdio.h>
#include<stdlib.h>

typedef struct Treenode * Tree;
struct Treenode
{
	int v;//储存节点的值
	Tree left, right;//储存左树的位置与右树的位置
};

Tree maketree(int n);//建立自平衡二叉树
Tree newnode(int v);//建立新节点
Tree insert(Tree T, int v);//向树中插入元素
int height(Tree T);//计算一个树的高度
Tree LLrotation(Tree T);//LL旋转,左单旋转
Tree LRrotation(Tree T);//LR旋转,左右双旋
Tree RRrotation(Tree T);//RR旋转,右单旋转
Tree RLrotation(Tree T);//RL旋转,右左双旋

int main()
{
	int n;
	scanf("%d", &n);
	Tree T;
	T = maketree(n);//构建AVL树
	printf("%d\n",T->v);//输出该树的根节点
	return 0;
}

Tree maketree(int n)
{
	int v;
	scanf("%d", &v);
	Tree T = newnode(v);//建立根节点
	for (int i = 1; i < n; i++)
	{
		scanf("%d", &v);
		T = insert(T,v);//首先插入形成新的二叉树;
	}
	return T;
}

Tree newnode(int v)
{
	Tree T = (Tree)malloc(sizeof(struct Treenode));
	T->v = v;
	T->left = T->right = NULL;
	//T->height = 1;
	return T;
}

Tree insert(Tree T, int v)
{
	if (!T) T = newnode(v);
	else
	{
		if (v < T->v )
		{
			T->left = insert(T->left, v);
			if (height(T->left) - height(T->right) == 2)//如果插入后左边的树高度达到2
			{
				if (v < T->left->v)//LL旋转
					T = LLrotation(T);
				else//LR旋转
					T = LRrotation(T);
			}
		}
		else
		{
			T->right = insert(T->right, v);
			if (height(T->right) - height(T->left) == 2)//如果插入后右边的树高度达到2
			{
				if (v < T->right->v)//RL旋转
					T = RLrotation(T);
				else//RR旋转
					T = RRrotation(T);
			}
		}
	}
	return T;
}

int height(Tree T)
{
	int hl, hr, max;
	if (T)
	{
		hl = height(T->left);
		hr = height(T->right);
		max = hl > hr ? hl : hr;
		return max + 1;
	}
	else
		return 1;
}

Tree LLrotation(Tree T)
{
	Tree a = T, b = T->left;//记录原来根节点,根节点的左节点
	Tree bl=b->left, br=b->right, ar=a->right;//记录三个需要旋转的树
	a->left = br;
	a->right = ar;
	b->left = bl;
	b->right = a;
	return b;
}


Tree LRrotation(Tree T)
{
	Tree a = T, b = T->left,c = b->right;//记录原来根节点,根节点的左节点,左节点的右节点
	Tree bl = b->left, cl = c->left, cr=c->right,ar = a->right;//记录四个需要旋转的树
	b->left = bl;
	b->right = cl;
	a->left = cr;
	a->right = ar;
	c->left = b;
	c->right = a;
	return c;
}

Tree RRrotation(Tree T)
{
	Tree a = T, b = T->right;//记录原来根节点,根节点的右节点
	Tree al = a->left, bl = b->left, br = b->right;//记录三个需要旋转的树
	a->left = al;
	a->right = bl;
	b->left = a;
	b->right = br;
	return b;
}

Tree RLrotation(Tree T)
{
	Tree a = T, b = T->right, c = b->left;//记录原来根节点,根节点的右节点,右节点的左节点
	Tree al=a->left,br=b->right,cl=c->left,cr=c->right;//记录四个需要旋转的树
	a->left = al;
	a->right = cl;
	b->left = cr;
	b->right = br;
	c->left = a;
	c->right = b;
	return c;
}

相关文章: