二叉树的遍历(非递归)

144. Binary Tree Preorder Traversal
94. Binary Tree Inorder Traversal
145. Binary Tree Postorder Traversal

二叉树遍历的递归写法可以说是十分简单,之所以简单是因为不需要人来维护栈,倘若让你显式地将这个栈模拟出来,事情就未必有你想的那样简单了。 -e-

#include<iostream>
#include<stack>

using namespace std;

#define ElemType char

typedef struct TreeNode {
    ElemType val;
    TreeNode * left;
    TreeNode * right;
} * BiTree;

void createBiTree(BiTree& root) {
    char ch = cin.get();
    if (' ' == ch)
        return;
    
    root = (BiTree)malloc(sizeof(TreeNode));
    root->val = ch;
    createBiTree(root->left);
    createBiTree(root->right);
    return;
}

void inorderTraverseRecursive(BiTree& root) {
    if (!root)
        return;
    inorderTraverseRecursive(root->left);
    cout << root->val;
    inorderTraverseRecursive(root->right);
    return;
}

// 二叉树的前序遍历(非递归)
void preorderTraversal(BiTree root) {
    stack<BiTree> stk;

    while (root || !stk.empty()) {
        while (root) {
            stk.push(root);
            cout << root->val;
            root = root->left;
        }
        root = stk.top();
        stk.pop();
        root = root->right;
    }
}

// 二叉树的中序遍历(非递归)
void inorderTraversal(BiTree root) {
    stack<BiTree> stk;
    
    // 请思考while的条件表达式为什么这样写
    // 1. 初始时栈是空的
    // 2. 在根结点退栈后根结点入栈前这个时间段,栈是空的
    
    while (root || !stk.empty()) {
        while (root) {
            stk.push(root);
            root = root->left;
        }
        root = stk.top();
        cout << root->val;
        stk.pop();
        root = root->right; 
        // 有没有发现这句其实还包含了root = nullptr;
    }

}

// 二叉树的后序遍历(非递归)
void postorderTraversal(BiTree root) {
    stack<BiTree> stk;
    BiTree pre = nullptr;

    // 请思考while的条件表达式为什么这样写
    // 1. 初始时栈是空的
    while (root || !stk.empty()) {
        while (root) {
            stk.push(root);
            root = root->left;
        }

        root = stk.top();
        
        // 若此结点有右孩子,并且此右孩子未被访问
        // 则应当令此右孩子入栈
        if (root->right && root->right!=pre) {
            root = root->right;
        } 
        // 若此结点无右孩子,或者该右孩子已被访问过
        // 则说明该结点的左右子树都已被访问
        // 令此结点出栈, 并且访问它
        else {
            cout << root->val;
            stk.pop();
            pre = root;
            root = nullptr; // 防止已出栈的指针再次进栈
            
        }
    }
}

int main() {
    BiTree root;
    createBiTree(root);
    
    inorderTraverseRecursive(root);
    cout << endl << "--------------" << endl;

    inorderTraversal(root);
    cout << endl << "--------------" << endl;
    preorderTraversal(root);
    cout << endl << "--------------" << endl;
    postorderTraversal(root);
    
    return 0;
}

三种遍历方式本质上其实都一样,只是访问根结点的时机不同(对于后序遍历还应判断该不该访问这个根结点)

指针进栈就是"递"的过程, 空指针跳过while (root)循环和指针出栈就是"归"的过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值