樹的定義,想必大家都不陌生,在樹正式進入前,我們需要回顧一下二叉樹的幾種遍歷方法,尤其很多題目都是圍繞樹的遞歸遍歷進行考察。
樹的遞歸遍歷
struct Node{
int val;
Node * left;
Node * right;
Node(int x) :val(x), left(nullptr), right(nullptr){};
};
void creatBinaryTree(Node * &root){ //樹的創建
int x;
cin >> x;
if (x == -1){
root = nullptr;
return;
}
root = new Node(x);
creatBinaryTree(root->left);
creatBinaryTree(root->right);
}
void visit(Node *T){ //樹的訪問
if (T->val != -1)
cout << T->val << " ";
}
/**遞歸方式遍歷**/
//先序遞歸遍歷
void preOrder(Node * root){
if (root != nullptr){
visit(root);
preOrder(root->left);
preOrder(root->right);
}
}
//中序遞歸遍歷
void inOrder(Node * root){
if (root != nullptr){
inOrder(root->left);
visit(root);
inOrder(root->right);
}
}
//後序遞歸遍歷
void postOrder(Node * root){
if (root != nullptr){
postOrder(root->left);
postOrder(root->right);
visit(root);
}
}
樹的非遞歸遍歷
LeetCode144. 二叉樹的前序遍歷
思路:棧壓入根節點,進行判空循環,設置一個指針p,其元素爲棧頂元素,出棧之後,將指針p所指的元素壓入容器res中;如果p節點有右孩子,則將右孩子入棧,之後再看p節點是否有左孩子,再將其左孩子入棧,先右後左的順序是因爲棧後進先出的規則;直到棧爲空,結束循環。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL) return res;
TreeNode* p = NULL;
s.push(root);
while(!s.empty()){
p = s.top();
s.pop();
res.push_back(p->val);
if(p->right) s.push(p->right);
if(p->left) s.push(p->left);
}
return res;
}
};
LeetCode94. 二叉樹的中序遍歷
思路:初始化p指針爲根節點,設置循環條件爲p指針不爲空或棧s不爲空;如果p指針不爲空,則將p節點入棧,p指針變爲其左孩子;若p指針爲空,則另p指針爲棧頂節點並出棧,將p指針所對應的元素壓入容器中,p指針變爲其右孩子。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL) return res;
TreeNode* p = root;
while(p || !s.empty()){
if(p){
s.push(p);
p = p->left;
}
else{
p = s.top();
s.pop();
res.push_back(p->val);
p = p->right;
}
}
return res;
}
};
LeetCode145. 二叉樹的後序遍歷
思路:棧壓入根節點,進行判空循環,設置一個指針p,其元素爲棧頂元素,出棧之後,將指針p所指的元素壓入容器res的開頭,這樣依次插入的元素在容器中是逆序的;如果p節點有左孩子,則將左孩子入棧,之後再看p節點是否有右孩子,再將其右孩子入棧;直到棧爲空,結束循環。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL) return res;
TreeNode* p = NULL;
s.push(root);
while(!s.empty()){
p = s.top();
s.pop();
res.insert(res.begin(), p->val);
if(p->left) s.push(p->left);
if(p->right) s.push(p->right);
}
return res;
}
};
LeetCode102. 二叉樹的層序遍歷 && 劍指 Offer 32 - II. 從上到下打印二叉樹 II
思路:根節點入隊,進行判空循環;隊頭元素出隊,依次判斷隊頭元素左右孩子是否存在,存在則依次入隊,我們會設置一個end來標記一層的最後一個節點,作爲一層遍歷的結束標誌,結束後,會將一層的信息壓入res容器中並清空臨時存放容器。
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
vector<int> tmp;
queue<TreeNode*> q;
TreeNode* end = root; //標記一層的最後一個節點
if (root == NULL) return res;
q.push(root);
while(!q.empty()){
tmp.push_back(q.front()->val);
if(q.front()->left != NULL) q.push(q.front()->left);
if(q.front()->right != NULL) q.push(q.front()->right);
if(q.front() == end){ //一層遍歷結束
end = q.back();
res.push_back(tmp);
tmp.clear();
}
q.pop();
}
return res;
}
};