【leetcode】二叉樹前、中、後序遍歷
前序遍歷
遞歸版本1
此解法比較簡單,先訪問 root 結點,然後用同樣的方法遞歸去訪問 root 結點的 left 結點然後是 root 結點的 right 結點,將他們放入容器vector中。注意這裏使用了遞歸的方法,遞歸越深,內存開銷越大:
class Solution {
public:
vector<int> ret;
vector<int> preorderTraversal(TreeNode* root) {
_prerder(root);
return ret;
}
void _prerder(TreeNode* root)
{
if (root)
{
ret.push_back(root->val);//訪問其根節點
_prerder(root->left);//遞歸左子樹
_prerder(root->right);//遞歸右子樹
}
}
};
遞歸優化版本
同樣也是先訪問 root 結點,然後用同樣的方法去訪問 root 結點的 left 結點
然後是 root 結點的 right 結點,將他們放入容器vector中。在這裏我使用了一個輔助函數 PushNode(), 該方法略微優化了一些,減少程序使用的內存
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
if (root) {
PushNode(root, result);
}
return result;
}
private:
void PushNode(TreeNode* root, vector<int> & v) {
if (root) {
v.push_back(root->val);
PushNode(root->left, v);
PushNode(root->right, v);
}
}
};
非遞歸實現
此種方法需要使用一個 stack 進行輔助,首先將 root 結點 push 到 棧中,然後就在一個 while 循環裏去取棧的頂部,並將其保存。然後壓棧 root 的right 結點,然後壓棧 root 的 left 結點。注意:這裏是前序遍歷,所以先壓棧 right 結點,是因爲棧 LIFO(後進先出)的特點。直至 取完棧爲空,可以清晰看出,內存消耗少了0.4MB。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> v;
if(root==NULL)
{
return v;
}
stack<TreeNode*> st;
TreeNode* tmp;
st.push(root);
while(!st.empty())
{
tmp=st.top();
v.push_back(tmp->val);
st.pop();
if(tmp->right!=NULL)
{
st.push(tmp->right);
}
if(tmp->left!=NULL)
{
st.push(tmp->left);
}
}
return v;
}
};
中序遍歷
遞歸版本
此解法跟前序遍歷一樣,先遞歸訪問 root 結點的left節點,然後去訪問 root 結點,最後是 遞歸root 結點的 right 結點,將他們放入容器vector中。注意這裏使用了遞歸的方法,遞歸越深,內存開銷越大:
class Solution {
public:
vector<int> v;
vector<int> inorderTraversal(TreeNode* root) {
_inorderTraversal(root);
return v;
}
void _inorderTraversal(TreeNode* root)
{
if(root)
{
_inorderTraversal(root->left);
v.push_back(root->val);
_inorderTraversal(root->right);
}
}
};
非遞歸版本
思路:用while循環找最左路節點,並將沿路的節點push_back到棧中,然後將指針tmp指向的最左路節點放入容器vector中,然後pop掉,就退回到了自身指向的val上,放入容器vector中,然後再指向其右路節點,直到棧中爲空結束。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> v;
if (root == NULL)
{
return v;
}
stack<TreeNode*> st;
TreeNode* tmp = root;
while (tmp || st.size())
{
while (tmp)//一直找到最左邊的節點,將所有左路節點,全部放入棧中
{
st.push(tmp);
tmp = tmp->left;
}
tmp = st.top();
st.pop();
v.push_back(tmp->val);
tmp = tmp->right;
}
return v;
}
};
後序遍歷
遞歸版本
此解法和前序遍歷一樣,用同樣的遞歸方法先去訪問 root 結點的 left 結點,然後是 root 結點的 right 結點,最後訪問 root 根結點,將他們放入容器vector中。注意這裏使用了遞歸的方法, 遞歸越深,內存開銷越大:
class Solution {
public:vector<int> v;
vector<int> postorderTraversal(TreeNode* root) {
_postorderTraversal(root);
return v;
}
void _postorderTraversal(TreeNode* root)
{
if (root)
{
_postorderTraversal(root->left);
_postorderTraversal(root->right);
v.push_back(root->val);
}
}
};
非遞歸版本
大致思路和前序遍歷一樣,就是最後把前序遍歷倒過來輸出就好了。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> v,res;
if(root==NULL)
{
return v;
}
stack<TreeNode*> st;
TreeNode* tmp;
st.push(root);
while(!st.empty())
{
tmp=st.top();
v.push_back(tmp->val);
st.pop();
if(tmp->left!=NULL)
{
st.push(tmp->left);
}
if(tmp->right!=NULL)
{
st.push(tmp->right);
}
}
for(int i=v.size()-1;i>=0;--i)
{
res.push_back(v[i]);
}
return res;
}
};