迭代(非递归)遍历二叉树

详解在代码注释,后序遍历比较复杂,主要因为在将某一点加入结果集时,需要判定它的左右子节点是否被访问过(已加入结果集),因此将访问过的节点值设为999,以便压栈时检查。

// 迭代先序
vector preorderTraversal(TreeNode* root) {
    vector ret;
    stack stk; // 辅助栈

    while (root || !stk.empty()) {
        while (root) {
            ret.push_back(root->val);   // 记录结果
            stk.push(root);
            root = root->left;
        }
        // 出栈
        auto node = stk.top();
        stk.pop();
        root = node->right;
    }
 
    return ret;
}


// 迭代后序
vector postorderTraversal(TreeNode* root) {
    vector ret;
    stack stk;

    while (root || !stk.empty()) {
        while (root && root->val != 999) {  // root不为空且未被访问过
            stk.push(root);
            root = root->left;
        }
        auto top = stk.top();   // 此时,top必然没有左子树,或者左子树被访问过  
        if (top->right && top->right->val != 999) {   
            // 没有左子树 + 有右子树,且右子树未被访问过,移动root到右子树,下一个循环开始压栈右子树里的节点
            root = top->right;
        } else {            
            // 没有左子树 + 没有右子树,或者有右子树但被访问过,当前节点加入结果集,并出栈
            ret.push_back(top->val);
            top->val = 999; // 标识当前节点已被访问过
            stk.pop();
        }
    }

    return ret;
}

// 迭代中序
vector inorderTraversal(TreeNode* root) {
    vector ret;
    stack stk;    // 辅助栈
    while (root || !stk.empty()) {  // 当root不为空时(还可以入栈)、或者栈不为空时(还可以出栈)
        // (1):当有左子树时,入栈
        while (root) {
            stk.push(root);
            root = root->left;
        }
        // (2):出栈,并判断出栈的节点是否有右子树
        // 如果有,以右子树为root从(1)处开始新一轮循环;
        // 如果没有,则继续出栈
        auto tmp = stk.top();
        stk.pop();
        ret.push_back(tmp->val);
        root = tmp->right; // 移动至右子树
    }
    return ret;
}

你可能感兴趣的:(算法)