Case1:滿二叉樹
題目描述
給出一棵滿二叉樹的先序遍歷,有兩種節點:字母節點(A-Z,無重復)和空節點(#)。要求這個樹的中序遍歷。輸出中序遍歷時不需要輸出#。滿二叉樹的層數n滿足1<=n<=5。
示例1
Sample Input: ABC#D#E
Sample Output:
CBADE
Solution:
滿二叉樹的特征很明顯,左右子樹結點個數相等,那么以某一個結點為根的子樹中,該根節點在先序遍歷中排在第一位,其在中序遍歷中一定排在最中間的位置上。利用分治的思想,建立一個數組,
根節點插入到數組中間位置,
左子樹根節點插入到數組左邊的中間位置,
一直這樣直至數組左邊中間位置已滿開始插入到右邊數組的中間位置,
依次遞歸 . . . . . .
以示例為例,遍歷前序遍歷字符串插入到數組中,最后輸出數組中字符串,即為中序遍歷字符串。
#include <iostream> #include <string.h> using namespace std; int i; // 全局變量,控制字符串的遍歷 string s; void insert(char a[], int left, int right){ // 將字符串各個元素插入數組對應位置 int mid = (left + right) / 2; if(left <= right && a[mid] != s[i]){ a[mid] = s[i++]; insert(a, left, mid-1); insert(a, mid+1, right); } } bool cimi2(int x){ // 判斷x是否是2的n次冪 return (x&(x-1))?false:true; } int main(){ while(cin>>s){ int n = s.length(); if(!cimi2(n+1)){ // 判斷是否是滿二叉樹 cout<<"不滿足滿二叉樹"<<endl; } else{ char *A = new char[n]; // 動態分配字符串數組 i = 0; int left = 0, right = n-1; insert(A, left, right); for(int j = 0; j < strlen(A); j++){ if(A[j] != '#'){ cout<<A[j]<<" "; } } cout<<endl; delete [] A; // 回收動態分配的字符串數組 } } return 0; }
Case2:無限制條件的二叉樹
題目描述
編一個程序,讀入用戶輸入的一串先序遍歷字符串,根據此字符串建立一個二叉樹(以指針方式存儲)。 例如如下的先序遍歷字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空樹。建立起此二叉樹以后,再對二叉樹進行中序遍歷,輸出遍歷結果。
輸入描述:
輸入包括1行字符串,長度不超過100。輸出描述:
可能有多組測試數據,對於每組數據, 輸出將輸入字符串建立二叉樹后中序遍歷的序列,每個字符后面都有一個空格。 每個輸出結果占一行。示例1
輸入
abc##de#g##f###
輸出
c b e g d f a
Solution1:
按照題目描述的那樣,根據輸入的前序遍歷字符串建立二叉樹,之后對該二叉樹進行中序遍歷。
#include <iostream> #include <string> using namespace std; string str; int i; struct TreeNode { char val; struct TreeNode *lchild, *rchild; TreeNode(char c) :val(c), lchild(NULL), rchild(NULL) {} }; TreeNode* createTree() { char c = str[i++]; if (c == '#') return NULL; TreeNode *root = new TreeNode(c); // 動態分配一個TreeNode類型存儲空間,返回類型為指針 root->lchild = createTree(); root->rchild = createTree(); return root; // 返回動態分配的指針 } void inOrderTraversal(TreeNode* root) { if (!root) return; inOrderTraversal(root->lchild); cout << root->val << " "; inOrderTraversal(root->rchild); } int main() { while (cin >> str) { i = 0; TreeNode *root = createTree(); inOrderTraversal(root); cout << endl;
delete [] root; // 動態分配的存儲空間要回收 } return 0; }
Solution2:
//這個實際上就是樹的遍歷的非遞歸實現,入棧時訪問 = 前序, 出棧時訪問 = 中序 #include <iostream> #include <string> #include <stack> using namespace std; int main() { string pre; while(cin >> pre){ stack<char> s; for(auto it : pre){ if(it != '#') s.push(it); else{ if(!s.empty()){ cout << s.top() << ' '; s.pop(); } } } cout << '\n'; } }
兩個題目很相似,第一個來自南京大學2018年研究生復試機試第一題;第二個來自牛客網清華大學復試機試題,代碼選取其中優秀提交代碼,但是對於不同要求的二叉樹,其處理方法還是有很大差異的,比如第一個情況建立滿二叉樹再遍歷是比較麻煩的。細細品味這兩道題,就能發現它們的精彩之處。