給定一個二叉樹,返回它的 前序 遍歷。
示例:
輸入: [1,null,2,3]
1
2
/
3
輸出: [1,2,3]
進階: 遞歸算法很簡單,你可以通過迭代算法完成嗎?
解題思路
1、如果採用遞歸思想的話,只需滿足根、左、右輸出即可。代碼簡單清晰,看看就會明白。
2、如果採用迭代,則有兩種思路:
a、一種是利用常規的迭代思想,利用輔助空間棧,按着先序遍歷的過程依次將節點輸出即可。先看根節點的左子樹是否爲空,如果不爲空,則從根節點開始依次將根節點和其左子樹的根節點壓入棧中,直到最左邊的葉子結點。同時將這些根節點的值輸出。然後在依次取出棧中元素,將其右節點作爲新的根節點,依次遍歷,直到棧爲空。
b、採用線索二叉樹的思想,利用兩個輔助指針實現迭代,空間複雜度爲O(1):
1、如果當前節點的左孩子爲空,則輸出當前節點並將其右孩子作爲當前節點。
2、如果當前節點的左孩子不爲空,在當前節點的左子樹中找到當前節點在中序遍歷下的前驅節點。
a) 如果前驅節點的右孩子爲空,將它的右孩子設置爲當前節點。輸出當前節點(在這裏輸出,這是與中序遍歷唯一一點不同)。當前節點更新爲當前節點的左孩子。
b) 如果前驅節點的右孩子爲當前節點,將它的右孩子重新設爲空。當前節點更新爲當前節點的右孩子。
3、重複以上1、2直到當前節點爲空。
代碼如下:
遞歸1
/*class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
preorder(root, res);
return res;
}
void preorder(TreeNode *root, vector<int> &res) {
if (!root)
return;
res.push_back(root->val);
if (root->left)
preorder(root->left, res);
if (root->right)
preorder(root->right, res);
}
};*/
遞歸2
/*class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
vector<int> res;
stack<int> res_;
preorder(root, res_);
while(!res_.empty()){
res.push_back(res_.top());
res_.pop();
}
return res;
}
void preorder(TreeNode *root, stack<int> &res) {
if (!root)
return;
if (root->right)
preorder(root->right, res);
if (root->left)
preorder(root->left, res);
res.push(root->val);
}
};*/
遞歸3
/*class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
if(root){
res.push_back(root->val);
preorderTraversal(root->left);
preorderTraversal(root->right);
}
return res;
}
private:
vector<int> res;
};*/
迭代1
/*class Solution{
public:
vector<int> preorderTraversal(TreeNode* root){
vector<int> res;
stack<TreeNode*> s;
TreeNode *p = root;
while(p){
s.push(p);
res.push_back(p->val);
p = p->left;
}
while(!s.empty()){
p = s.top();
p = p->right;
s.pop();
while(p != NULL){
s.push(p);
res.push_back(p->val);
p = p->left;
}
}
return res;
}
};*/
迭代2
// 不用遞歸和輔助空間棧,空間複雜度爲O(1).
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
vector<int> res;
if (!root)
return res;
TreeNode *cur, *pre;
cur = root;
while (cur) {
if (!cur->left) {
res.push_back(cur->val);
cur = cur->right;
}
else {
pre = cur->left;
while (pre->right && pre->right != cur) //找出cur的前驅節點
pre = pre->right;
if (!pre->right) {
pre->right = cur;
res.push_back(cur->val);
cur = cur->left;
}
else {
pre->right = NULL;
cur = cur->right;
}
}
}
return res;
}
};
迭代3
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL){
return res;
}
TreeNode *cur = root;
while(cur || !s.empty()){
if(cur != NULL){
res.push_back(cur->val);
s.push(cur->right);
cur = cur->left;
}
else {
cur = s.top();
s.pop();
}
}
return res;
}
};
關於利用線索二叉樹實現遍歷的,可參考:https://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html