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