PAT1066--Root of AVL Tree (25)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/grooowing/article/details/44591463

http://www.patest.cn/contests/pat-a-practise/1066

原题的描述就不再复述了。

这道题我从昨晚开始,做了七个小时。哭

从这道题的各种波折来看,我存在如下几个编程上的问题:

1,原本我以为自己在树的结构方面是很清晰的,可是事实并不是这样。我在写,树的高度,树的遍历和插入查找二叉树时遇到了很多问题。原因一方面可能是我没有真正用“树”的结构,而是用相当于数组的结构代替的,其次是递归理解的不好,不知道如何利用返回值。

2,既然自己定义了数据结构,自己都不知道里面需要有多少元素,在需要修正的时候也忘了修正。比如,我既然有了parent参数,在修改是,只注意了lchild,和rchild的修改,忘记了parent也需要修改。以及忘了查看是插入左子树还是右子树。(在change()函数里)

下面来写一下本题的思路:

数据结构定义:

typedef struct node{
	int left,right;
	int parent;
	int x;
	int xuhao;
	int h;
	int delth;
}Tree;
之所以这么定义数据结构,是因为我用习惯了,有时候这种带xuhao的结构很方便。不过,后来感觉我应该直接用指针的。

整体的思路就是:

扫描二维码关注公众号,回复: 4913493 查看本文章

1,插入二叉树-->函数insert()

2,计算左右子树高度差-->height()

3,找到最下面一个非平衡点(左右字数高度差为2,或-2)-->findunblc()

4,确定种类,是LL,LR,RR还是RL,-->kind()不知道这四个名词的同学请查阅资料简单了解一下AVL树的变换,你只要了解了,就可以轻松编写本体很关键的代码了。

5,变换-->change()

以下是源代码,建议拷贝到环境中删掉我的处世代码查看(/**/注释的内容)

本体最重要的还是了解如何变换使树平衡。

可以参考:http://blog.chinaunix.net/uid-25324849-id-2182877.html

主函数里有很多调试信息。

#include<stdio.h>
#include<queue>
using namespace std;
#define LL 0
#define LR 1
#define RR 2
#define RL 3


//数据结构
typedef struct node{
	int left,right;
	int parent;
	//x是插入的数字
	int x;
	//序号,即分配的数组下标,本程序貌似没用到
	int xuhao;
	//高度和高度差
	int h;
	int delth;
}Tree;

//树的数组,root为树根,0表示空
Tree tree[21];
int root;
//分配一个树结构
//相当于malloc();
int coun;
int apply(){
	return ++coun;
}

//返回最大值;
int max(int x,int y){
	return x>y?x:y;
}

//计算节点的高度,并计算左右子树高度差
//对不起,这里我不想去掉我修改的内容,因为我未来要
//参考,看看我此时的弱点。。。
//很明显,一开始我没有处理好递归出口
//树的递归出口很多都是if(root==0)...
int height(int root){
	if(root==0)return 0;
	int lefth=0,righth=0;
	/*if(tree[root].left==0 && tree[root].right==0)
		return 1;
	int lefth=0,righth=0;

	if(tree[root].left==0)
		righth=height(tree[root].right);
	else if(tree[root].right==0)
		lefth=height(tree[root].left);*/
	//else{	
	lefth=height(tree[root].left);
	righth=height(tree[root].right);
	//}
	tree[root].h=max(lefth,righth)+1;
	tree[root].delth=lefth-righth;

	return tree[root].h;
}

//因为要找最后一个不平衡点(-2或者2),
//所以我选择层次遍历,用了队列
int findunblc(int root){
	if(root==0)return 0;
	int res=0;
	queue<int> Q;
	while(!Q.empty())Q.pop();
	Q.push(root);
	while(!Q.empty()){
		int t=Q.front();
		Q.pop();
		if(tree[t].left!=0)
			Q.push(tree[t].left);
		if(tree[t].right!=0)
			Q.push(tree[t].right);
		if(tree[t].delth>1 || tree[t].delth<-1)
			res=t;
	}
	return res;
}

//查找函数,返回下标(指针)
//没有用到,因为后来修改了kind()算法
//本来我决定是用search的方式来判定LL等的
int search(int root,int x){
	if(root==0)
		return 0;
	if(tree[root].x==x)
		return root;
	if(tree[root].x>x){
		return search(tree[root].right,x);
	}
	else{
		return search(tree[root].left,x);
	}
}

//判定修改种类,不需修改返回-1;
int kind(int root){
	/*int left=tree[root].left,right=tree[root].right;
	if(left!=0 && tree[left].left!=0){
		if(search(tree[left].left,x)!=0)
			return LL;
	}
	if(left!=0 && tree[left].right!=0){
		if(search(tree[left].right,x)!=0)
			return LR;
	}
	if(right!=0 && tree[right].right!=0){
		if(search(tree[right].right,x)!=0)
			return RR;
	}
	if(right!=0 && tree[right].left!=0){
		if(search(tree[right].left,x)!=0)
			return RL;
	}
	return 0;*/
	int left=tree[root].left,right=tree[root].right;
	if(tree[root].delth==2 && tree[left].delth==1)
		return LL;
	if(tree[root].delth==2 && tree[left].delth==-1)
		return LR;
	if(tree[root].delth==-2 && tree[right].delth==-1)
		return RR;
	if(tree[root].delth==-2 && tree[right].delth==1)
		return RL;
	return -1;

}

//旋转函数,注意打了///////////的是变化parent,
//一开始我忘了
void change(int center){//all's root

	int temp1,temp2,temp3,temp4;
	int res=kind(center);
	switch(res){
	case LL:
		if(center==root){//if center is the root
			root=tree[center].left;
			tree[root].parent=0;//////////////////
		}
		//else
			//tree[tree[center].parent].left=tree[center].left;
		else{
			temp2=tree[center].left;
			if(tree[tree[center].parent].left == center)
				tree[tree[center].parent].left=temp2;
			else
				tree[tree[center].parent].right=temp2;
			tree[temp2].parent=tree[center].parent;/////////////////
		}

		temp1=tree[center].left;
		tree[center].left=tree[temp1].right;
		tree[tree[temp1].right].parent=center;///////////////
		tree[temp1].right=center;
		tree[center].parent=temp1;///////////////////
		break;
	case LR:
		if(center==root){
			root=tree[tree[center].left].right;
			tree[root].parent=0;/////
		//else
			//tree[tree[center].parent].left=tree[tree[center].left].right;
		}
		else{
			temp2=tree[tree[center].left].right;
			if(tree[tree[center].parent].left == center)
				tree[tree[center].parent].left=temp2;
			else
				tree[tree[center].parent].right=temp2;
			tree[temp2].parent=tree[center].parent;/////////////
		}
		temp1=tree[center].left;
		temp2=tree[temp1].right;
		temp3=tree[temp2].left;
		temp4=tree[temp2].right;

		tree[temp2].right=center;
		tree[center].parent=temp2;//////////
		tree[temp2].left=temp1;
		tree[temp1].parent=temp2;//////////
		tree[temp1].right=temp3;
		tree[temp3].parent=temp1;////////////
		tree[center].left=temp4;
		tree[temp4].parent=center;//////////

		break;
	case RR:
		if(center==root){
			root=tree[center].right;
			tree[root].parent=0;
		//else//一开始忘记查看是插入parent左子树还是右子树了
			//tree[tree[center].parent].right=tree[center].right;
		}
		else{
			temp2=tree[center].right;
			if(tree[tree[center].parent].left == center)
				tree[tree[center].parent].left=temp2;
			else
				tree[tree[center].parent].right=temp2;
			tree[temp2].parent=tree[center].parent;/////////
		}
		temp1=tree[center].right;
		tree[center].right=tree[temp1].left;
		tree[tree[temp1].left].parent=center;////////////
		tree[temp1].left=center;
		tree[center].parent=temp1;/////////////

		break;
	case RL:
		temp1=tree[center].right;
		temp2=tree[temp1].left;
		temp3=tree[temp2].left;
		temp4=tree[temp2].right;
		if(center==root){
			root=temp2;
			tree[root].parent=0;//////////
		}
		else{
			if(tree[tree[center].parent].left == center)
				tree[tree[center].parent].left=temp2;
			else
				tree[tree[center].parent].right=temp2;
			tree[temp2].parent=tree[center].parent;////////
		}

		tree[temp2].right=temp1;
		tree[temp1].parent=temp2;///////////
		tree[temp2].left=center;
		tree[center].parent=temp2;//////////
		tree[center].right=temp3;
		tree[temp3].parent=center;/////////
		tree[temp1].left=temp4;
		tree[temp4].parent=temp1;//////////

		break;
	default:
		break;	
	}
	//printf("kind is %d\n",res);
}

//插入函数,引入参数p是想记录父亲
int insert(int root,int x,int p){
	if(root==0){
		int r=apply();
		////////////////////////
		//printf("apply:%d\n",r);
		tree[r].left=0;
		tree[r].right=0;
		tree[r].parent=p;
		tree[r].xuhao=coun;
		tree[r].x=x;
		root=r;
		return r;
		
	}
	if(x>tree[root].x){
		tree[root].right=insert(tree[root].right,x,root);
	}
	else
		tree[root].left=insert(tree[root].left,x,root);
	return root;
}

//遍历,用于debug
void preorder(int root){
	if(root!=0)
		printf("%d ",tree[root].x);
	else return;
	preorder(tree[root].left);
	preorder(tree[root].right);
}

void inorder(int root){
	if(root==0)
		return;
	inorder(tree[root].left);
	if(root!=0)
		printf("%d ",tree[root].x);
	inorder(tree[root].right);
}


		
int main(){
	//while(true){
		int N,x;
		int i;
		root=0,coun=0;
		scanf("%d",&N);
		for(i=0;i<N;i++){
			scanf("%d",&x);
			root=insert(root,x,0);
			//preorder(root);
			//puts("");
			//inorder(root);
			//puts("");
			//puts("OK");
			height(root);
			int center=findunblc(root);
			//printf("root:%d,dheight:%d\n",root,tree[root].delth);
			//printf("center:%d\n",tree[center].x);//
			change(center);
			//height(root);//
			//printf("root.x:%d,dheight:%d\n",tree[root].x,tree[root].delth);//
			
			//printf("answer:%d\n",tree[root].x);
		}
		printf("%d\n",tree[root].x);
		//printf("%d\n",);
	//}
	return 0;
}





猜你喜欢

转载自blog.csdn.net/grooowing/article/details/44591463