根據前序遍歷判斷二叉搜尋樹
阿新 • • 發佈:2019-01-05
題意:給你一個二叉樹的前序遍歷序列,讓你判斷是不是二叉搜尋樹(左子樹小於根,右子樹大於根)或其映象。如果是,輸出後序遍歷序列。
開始走了彎路,一直在思考如何建樹,結果試了很多種方法都不對,總是在一個新節點該放在哪個節點下出問題。
其實這道題可以和給出前序中序寫後序這種題類比,完全可以不建樹。根據前序遍歷的性質每次可以把根節點分離出來;根據二叉搜尋樹的性質每次可以把左右子樹分開;這樣在判斷的時候只判斷左邊的是不是都小於根,右邊的是不是都大於根就行了。至於後續序列,在遞迴左右之後,用b陣列儲存。
#include <stdio.h> #include <algorithm> using namespace std; int a[1003], n, k = 0, b[1003]; int check1(int l, int r) { if(l > r) return 1; int root = a[l];//把根節點拿出來 int i, j; for(i = l + 1 ; i <= r && a[i] < root; i++);//根據二叉搜尋樹的性質,把左右子樹分開 for(j = i ; j <= r ; j++)//檢查右子樹是不是都大於根 { if(a[j] < root) return 0; } if(check1(l + 1, i - 1) == 0)//遞迴地檢查左右子樹 return 0; if(check1(i, r) == 0) return 0; b[k++] = a[l];//b儲存後序遍歷序列 return 1; } int check2(int l, int r) { if(l > r) return 1; int root = a[l]; int i, j; for(i = l + 1 ; i <= r && a[i] >= root; i++); for(j = i ; j <= r ; j++) { if(a[j] >= root) return 0; } if(check2(l + 1, i - 1) == 0) return 0; if(check2(i, r) == 0) return 0; b[k++] = a[l]; return 1; } int main() { int i; scanf("%d", &n); for(i = 1 ; i <= n ; i++) scanf("%d", &a[i]); if(n == 1) { printf("YES\n%d\n", a[1]); return 0; } if(a[1] > a[2]) { if(check1(1, n)) { printf("YES\n"); for(i = 0 ; i < n - 1 ; i++) printf("%d ", b[i]); printf("%d\n", b[n - 1]); } else printf("NO\n"); } else { if(check2(1, n)) { printf("YES\n"); for(i = 0 ; i < n - 1 ; i++) printf("%d ", b[i]); printf("%d\n", b[n - 1]); } else printf("NO\n"); } return 0; }