二叉树的遍历方式(递归、非递归)

二叉树的前序、中序、后序遍历方式,递归与非递归。(层序遍历的方式已经在之前的博客中写过)

递归方式比较简单。

前序遍历:

void preorder(TreeNode* root){
       if (root){
        cout << root -> val << endl;
        preorder(root -> left);
        preorder(root -> right);
       }
}

 前序遍历非递归:

基本思路:  利用栈。先输出结点值,再入栈。然后遍历左子树。退栈时,遍历栈顶结点的右子树。

void preorder(const TreeNode* root){
    stack<TreeNode*> s;
    TreeNode* p = root;
    while (p || !s.empty()){
        if (p){
            cout << p -> data << " ";
            s.push(p);
            p = p -> left;
        }
        else{
            p = s.top();
            s.pop();
            p = p -> right;  
        }
    }

}

 中序遍历非递归:  先进栈,再遍历左子树,出栈时才会输出结点值

void inorder(TreeNode* root){
    stack<TreeNode*> s;
    TreeNode* p = root;
    while (p || !s.empty()){
        if (p){
            s.push(p);
            p = p -> left;
        }
        else{
            p = s.top();
            s.pop();
            cout << p ->val << " ";   // 注意与前序遍历只有一行代码的不同
            p = p -> right;
        }
    }
}

 后序非递归:

    用一个bool变量标识结点p的右子树的遍历的状态。不太理解为什么要标记右子树的状态?

void postorder(TreeNode* root){
    stack<pair<TreeNode*, bool> s;
    TreeNode* p = root;
    while (p || s.empty()){
        if (p){
            s.push(make_pair(p, false));   // false 表示右子树未被访问
            p = p -> left;
        }
        else {
            if (s.top().second == false){  // 表示根节点的右子树还未访问
                s.top().second = true;
                p = s.top().first -> right;     // 去遍历右子树
            }
            else{   // 右子树已经访问
                cout << s.top().first -> val << " ";  // 输出根节点的值
                s.pop();                              // 根结点退栈
            }
        }
    }
}