1. 程式人生 > >LeetCode 144 ——二叉樹的前序遍歷

LeetCode 144 ——二叉樹的前序遍歷

1. 題目

2. 解答

2.1. 遞迴法

定義一個存放樹中資料的向量 data,從根節點開始,如果節點不為空,那麼

    1. 將當前節點的數值加入到 data 中
    1. 遞迴得到其左子樹的資料向量 temp,將 temp 合併到 data 中去
    1. 遞迴得到其右子樹的資料向量 temp,將 temp 合併到 data 中去
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        
        vector<int> data = {};
        vector<int> temp = {};

        if (root != NULL)
        {
            data.push_back(root->val);
            temp = preorderTraversal(root->left);
            data.insert(data.end(),temp.begin(),temp.end());
            temp = preorderTraversal(root->right);
            data.insert(data.end(),temp.begin(),temp.end());
        }
        
        return data;         
    }
};
2.2. 迭代法

定義一個存放樹中節點的棧 node_stack 和存放資料的向量 data,從根節點開始,如果節點不為空或者棧非空,迴圈以下過程:

    1. 如果節點非空,將節點的值加入 data,如果節點有右孩子,將節點右孩子壓入棧,節點指向其左孩子,迴圈直到節點為空
    1. 如果節點為空,棧非空,則彈出棧頂節點
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {

        vector<int> data = {};
        stack<TreeNode*> node_stack;
        TreeNode* temp = root;
        
        while (temp || !node_stack.empty())
        {
            while(temp != NULL)
            {
                data.push_back(temp->val);
                if (temp->right)    node_stack.push(temp->right);
                temp = temp->left;
            }
            
            // 若最後一個節點沒有右子節點,棧為空
            if (!node_stack.empty()) // 棧非空
            {
                temp = node_stack.top();
                node_stack.pop();
            }
        }
        
        return data; 
    }
};
2.3. Morris 遍歷法

前面兩種方法要麼需要函式棧要麼需要人工棧,其空間複雜度為 \(O(n)\),而 Morris 遍歷法可以做到在不影響時間複雜度的情況下做到空間複雜度為 \(O(1)\)

定義一個存放資料的向量 data,從根節點開始,如果當前節點非空,迴圈以下過程:

    1. 如果當前節點沒有左孩子,將當前節點的值加入到 data 中,當前節點指向其右孩子
    1. 如果當前節點有左孩子,則尋找當前節點的前驅節點,即節點值小於該節點值並且值最大的節點,也即當前節點左子樹中值最大的節點
    • a) 如果前驅節點沒有右孩子,前驅節點右孩子指向當前節點,將當前節點的值加入到 data 中,當前節點指向其左孩子
    • b) 如果前驅節點右孩子為當前節點,當前節點指向其右孩子,前驅節點右孩子設為空(恢復原有樹結構)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {

        vector<int> data = {};
        TreeNode* cur = root;
        TreeNode* pre = NULL;

        while (cur)
        {
            if (cur->left == NULL)
            {
                data.push_back(cur->val);
                cur = cur->right;
            }
            
            else
            {

                // 尋找前驅結點
                pre = cur->left;
                while (pre->right != cur && pre->right)
                {
                    pre = pre->right;
                }
                
                if (pre->right == NULL)
                {
                    data.push_back(cur->val);
                    pre->right = cur;
                    cur = cur->left;
                }
                else
                {
                    cur = cur->right;
                    pre->right = NULL;
                }
            }
        }
        
        return data;
        
    }
};

參考資料

獲取更多精彩,請關注「seniusen」!