PAT1066--Root of AVL Tree (25)

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的結構很方便。不過,後來感覺我應該直接用指針的。

整體的思路就是:

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;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章