PAT1066--Root of AVL Tree (25)
阿新 • • 發佈:2019-01-14
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; }