試題 歷屆試題 橫向列印二叉樹
二叉樹可以用於排序。其原理很簡單:對於一個排序二叉樹新增新節點時,先與根節點比較,若小則交給左子樹繼續處理,否則交給右子樹。
當遇到空子樹時,則把該節點放入那個位置。
比如,10 8 5 7 12 4 的輸入順序,應該建成二叉樹如下圖所示,其中.表示空白。
...|-12 10-| ...|-8-| .......|...|-7 .......|-5-| ...........|-4
本題目要求:根據已知的數字,建立排序二叉樹,並在標準輸出中橫向列印該二叉樹。
輸入格式輸入資料為一行空格分開的N個整數。 N<100,每個數字不超過10000。
輸入資料中沒有重複的數字。
輸出格式輸出該排序二叉樹的橫向表示。為了便於評卷程式比對空格的數目,請把空格用句點代替:
樣例輸入1 10 5 20 樣例輸出1...|-20 10-| ...|-5樣例輸入2 5 10 20 8 4 7 樣例輸出2
.......|-20 ..|-10-| ..|....|-8-| ..|........|-7 5-| ..|-4
這題初看,除了知道這些數值是自頂向下遞減的,其他沒什麼頭緒,然後看了網上的一些程式碼,但是本人的程式碼閱讀能力有些差,還是實力太差了,所以愣是看不大懂,不過總算也提取了些重要的資訊.
1.宣告一個變數用於儲存根節點的值;
2.開闢兩個陣列L[]和R[]分別用於儲存每個節點的左子樹和右子樹的資訊;
3.寫一個add()函式處理新增新節點的操作.
瞭解了這些之後我就開始自己在紙上寫寫畫畫,既然知道了節點的行號,那麼也要確定其列號才行,然後發現除了根節點列號為0,每個節點的列號正好是其父節點的列號+父節點的數值長度+3(這個3即"-|-"的長度),於是我開闢了一個數組pos[]用於記錄節點的列號,陣列len[]記錄數字長度. 於是寫出如下(有bug的)程式碼:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4#include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <algorithm> 8 #define INF 0x3f3f3f3f 9 #define zero 1e-7 10 11 using namespace std; 12 typedef long long ll; 13 const ll mod=1e9+7; 14 const ll max_n=105; 15 16 int a[max_n]={0};//記錄輸入的數字 17 int L[max_n]={0};//記錄節點的左子樹 18 int R[max_n]={0};//記錄節點的右子樹 19 int pos[max_n]={0};//記錄節點的列號 20 int len[max_n]={0};//記錄數字的長度 21 22 //新增新節點 23 void add(int r, int x) { 24 if(x<r) {//若x<r則將x交給r的左子樹處理 25 if(!L[r]) {//若r的左子樹為空,則將x放入這個位置 26 L[r]=x; 27 pos[x]=pos[r]+len[r]+3;//x的列號,3是"-|-"的長度 28 } 29 else { 30 add(L[r], x); 31 } 32 } 33 else {//否則將x交給r的左子樹處理 34 if(!R[r]) { 35 R[r]=x; 36 pos[x]=pos[r]+len[r]+3; 37 } 38 else { 39 add(R[r], x); 40 } 41 } 42 } 43 44 int main() { 45 int k=0;//k記錄輸入數字的個數 46 int root;//記錄根節點的值 47 while(cin>>a[k]) { 48 int temp=a[k]; 49 while(temp) {//計算數字a[k]的長度 50 len[a[k]]++; 51 temp/=10; 52 } 53 if(!k) {//第一個輸入的數字是根節點 54 root=a[k]; 55 pos[a[k]]=0; 56 } 57 else { 58 add(root, a[k]); 59 } 60 k++; 61 } 62 sort(a, a+k, greater<int>());//按降序排列,由排序二叉樹的特性可知,自頂往下數值越小 63 for(int i=0; i<k; i++) {//列印輸出 64 for(int j=0; j<pos[a[i]]-2; j++) { 65 cout<<'.'; 66 } 67 if(a[i]!=root) cout<<"|-"; 68 cout<<a[i]; 69 if(L[a[i]] || R[a[i]]) cout<<"-|"; 70 cout<<endl; 71 } 72 return 0; 73 }
執行之後輸出是這樣的(Ctrl+Z+回車 結束輸入得結果)——
沒錯,漏了好幾個'|',因為我只在節點前面添加了'|',而忽略了每個父節點從其右子樹到左子樹的縱向之間的'|',這可如何是好,想了想,於是我開闢了一個二維陣列mp[][]用於記錄數字前面的'.','|' 和'-',並寫了兩個迴圈,一個用於填滿每行數字前面的'.','|'和'-',一個用於專門處理每個父節點從其右子樹到左子樹的縱向之間的'|',也就是64~89行的程式碼,當然列印輸出那裡也改了一下,以下是修改後的AC程式碼——
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <algorithm> 8 #define INF 0x3f3f3f3f 9 #define zero 1e-7 10 11 using namespace std; 12 typedef long long ll; 13 const ll mod=1e9+7; 14 const ll max_n=105; 15 16 char mp[max_n][max_n];//記錄數字前面的'.','|' 和'-' 17 int a[max_n]={0};//記錄輸入的數字 18 int L[max_n]={0};//記錄節點的左子樹 19 int R[max_n]={0};//記錄節點的右子樹 20 int pos[max_n]={0};//記錄節點的列號 21 int len[max_n]={0};//記錄數字的長度 22 23 //新增新節點 24 void add(int r, int x) { 25 if(x<r) {//若x<r則將x交給r的左子樹處理 26 if(!L[r]) {//若r的左子樹為空,則將x放入這個位置 27 L[r]=x; 28 pos[x]=pos[r]+len[r]+3;//x的列號,3是"-|-"的長度 29 } 30 else { 31 add(L[r], x); 32 } 33 } 34 else {//否則將x交給r的左子樹處理 35 if(!R[r]) { 36 R[r]=x; 37 pos[x]=pos[r]+len[r]+3; 38 } 39 else { 40 add(R[r], x); 41 } 42 } 43 } 44 45 int main() { 46 int k=0;//k記錄輸入數字的個數 47 int root;//記錄根節點的值 48 while(cin>>a[k]) { 49 int temp=a[k]; 50 while(temp) {//計算數字a[k]的長度 51 len[a[k]]++; 52 temp/=10; 53 } 54 if(!k) {//第一個輸入的數字是根節點 55 root=a[k]; 56 pos[a[k]]=0; 57 } 58 else { 59 add(root, a[k]); 60 } 61 k++; 62 } 63 sort(a, a+k, greater<int>());//按降序排列,由排序二叉樹的特性可知,自頂往下數值越小 64 //這個迴圈是將每行的數字前面填滿'.','|'和'-' 65 for(int i=0; i<k; i++) { 66 int j; 67 for(j=0; j<pos[a[i]]-2; j++) { 68 mp[i][j]='.'; 69 } 70 mp[i][j++]='|'; 71 mp[i][j]='-'; 72 } 73 //這個迴圈是處理每個節點從其右子樹到左子樹的縱向之間的'|' 74 for(int i=0; i<k; i++) { 75 int temp=pos[a[i]]+len[a[i]]+1;//這是節點a[k]右邊的'|'的列號 76 if(R[a[i]]) {//若該節點有右子樹 77 for(int j=i-1; ; j--) {//往上 78 if(a[j]>=R[a[i]]) break; 79 mp[j][temp]='|'; 80 } 81 } 82 if(L[a[i]]) {//若該節點有左子樹 83 for(int j=i+1; ; j++) {//往下 84 if(a[j]<=L[a[i]]) break; 85 mp[j][temp]='|'; 86 } 87 } 88 } 89 for(int i=0; i<k; i++) {//列印輸出 90 for(int j=0; j<pos[a[i]]; j++) 91 cout<<mp[i][j]; 92 cout<<a[i]; 93 if(L[a[i]] || R[a[i]]) cout<<"-|"; 94 cout<<endl; 95 } 96 return 0; 97 }