1. 程式人生 > >二叉樹深度優先遍歷詳解

二叉樹深度優先遍歷詳解

二叉樹的遍歷(每一種遍歷次序有遞迴實現(簡捷)和迭代實現兩種方式)


深度優先遍歷

1.遞迴實現

中根遍歷的遞迴實現

    vector<int> result;
    vector<int> inorderTraversal(TreeNode* root) {
        inorder(root);
        return result;
    }
    void inorder(TreeNode* root){
        if(root == nullptr){
            return;
        }
        inorder(root->left);
        result.push_back(root->val);
        inorder(root->right);     

}

其他順序的遍歷只需調換順序即可。

2.迭代實現 

先根遍歷(先序遍歷)

例如下圖中左邊的單元,在先根遍歷中,列印1,然後進入以2為根節點的下一個單元,倘若2為NULL,那麼便進入3為根節點的下一個單元。


根節點→左子節點→右子節點,1,2,4,7,3,5,6,8

思路:迭代實現最重要的就是對路徑的儲存與回溯,如果不考慮上述內容,單單對每一次的迭代步驟進行實現,然後一路向下。

先根遍歷實現的程式碼為:

If(cur!= NULL)  cout << cur->val;  
If(cur->left != NUll)cur=cur->left
Else cur = cur->right;
加入對路徑的記憶,將1到2的路徑記為第一路徑,將1到3的路徑記為第二路徑。將路徑的終點按照第一路徑在上,第二路徑在下的順序壓入棧中。

加入對路徑的記憶和提取

cur = s.top();  s.pop(); //從堆疊中提取路徑
cout << cur->val;     //列印,列印後的路徑不用記憶
if(cur->right != NULL) s.push(cur->right);  
if(cur->left != NULL) s.push(cur->left);               //記憶路徑用於下一步的迭代
完整程式碼
vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack< TreeNode *> s;
        TreeNode *cur;
        if(root != NULL){
           s.push(root);
        }
        while(!s.empty()){
            cur = s.top();
            s.pop();
            result.push_back(cur->val);
            if(cur->right != NULL) s.push(cur->right);
            if(cur->left != NULL) s.push(cur->left);
        }
        return result;
}

中根遍歷(中序遍歷)

顧名思義,中根遍歷的根位於結果序列的中間

左子節點→根節點→右子節點,4,7,2,1,3,5,8,6

以下圖為例,在中根遍歷中,直接進入以2為根節點的單元,若2為空,列印1,進入以3為根節點的單元。                 

先根遍歷的基本邏輯實現為:

If(cur!= nullptr) cur = cur->left
Else cout << cur; cur = cur->right;

加入對於路徑的記憶和提取,只需要在進入左子節點之前記錄根節點即可。

If(cur != nullptr) {
    S.push_back(cur);
    cur = cur->left;
}else
{
    cur = s.top();
    s.pop();
    result.push_back(cur->val);
    cur = cur->right;
}
完整程式碼為
vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<const TreeNode *> s;
        const TreeNode *cur = root;
        while(!s.empty() || cur != nullptr){
            if(cur!= nullptr)
            {
                s.push(cur);
                cur = cur->left;
            }else
            {
                cur = s.top();
                s.pop();
                result.push_back(cur->val);
                cur = cur->right;
            }
        }
        return result;
    }

後根遍歷(後序遍歷)

左子節點→右子節點→根節點

N74N258N631

後根遍歷和先根遍歷的順序是完全相反的,所以可以依據先根遍歷的演算法,得到結果後,再將結果反轉過來即可。另外一種方法,太複雜,思路上屢不清,算了。

vector<int> postorderTraversal(TreeNode* root) {
    vector<int> v;
    if (!root) return v;
    stack<TreeNode *> s;
    s.push(root);
    TreeNode *p = NULL;
    while(!s.empty()) {
        p = s.top();
        s.pop();
        v.insert(v.begin(), p->val);
        if (p->left) s.push(p->left);
        if (p->right) s.push(p->right);
    }
    return v;
    }