题目
(1)给你一棵二叉树的根节点 root ,返回其节点值的后序遍历 。
(2)示例如下
输入:root = [1,null,2,3]
输出:[3,2,1]
解决思路
- 前序遍历顺序:根节点 -> 左节点 - >右节点;中序遍历:左节点 -> 根节点 -> 右节点;后续遍历:左节点 -> 右节点 -> 根节点。
- 二叉树遍历适合采用递归的思想解决。
- 使用两个栈(数据栈和状态栈)模拟递归过程,即采用非递归函数实现递归功能。
代码
- C++代码
# include <stdio.h>
# include <vector>
# include <stack>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(): val(0), left(nullptr), right(nullptr) {}
TreeNode(int x): val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right): val(x), left(left), right(right) {}
};
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
if (nullptr == root) {
return vector<int>();
}
vector<int> ret;
stack<TreeNode*> s1; // 数据栈,存储相关节点的数据,即递归过程中的局部变量。
stack<int> s2; // 程序状态栈,根据当前状态判断采取什么操作。如记录当前节点压入了左子树还是右子树。0:压入左子树,1:压入右子树,2:输出根节点的值。
s1.push(root); // 初始化:将根节点压入数据栈中。
s2.push(0); // 初始化:当前根节点对应的操作为压入左子树(即遍历左子树)。
// 从根节点开始遍历,遍历左子树即将左子树压入数据栈,遍历右子树即将右子树压入数据栈,遍历根节点即输出根节点的值。
while (!s1.empty()) {
int status = s2.top(); // 获取当前根节点的操作状态。
s2.pop(); // 弹出当前节点的操作状态。
// 对当前节点的具体操作
switch (status) {
case 0: // 第一步:遍历当前根节点的左子树
s2.push(1); // 当前根节点的状态码由0转为1,即下一步遍历当前根节点的右节点
if (s1.top()->left) { // 当前根节点的左节点存在。
s1.push(s1.top()->left); // 将当前根节点的左节点压入数据栈。
s2.push(0); // 将操作状态压入栈,0:遍历左节点。
}
break;
case 1: // 第二步:遍历当前根节点的右子树
s2.push(2); // 当前根节点的状态码由1转为2,即下一步输出当前根节点的值
if (s1.top()->right) {
s1.push(s1.top()->right);
s2.push(0);
}
break;
case 2: // 第三步:遍历根节点,输出根节点的值,并弹出根节点
ret.push_back(s1.top()->val);
s1.pop();
break;
default:
break;
}
}
return ret;
}
};
int main() {
Solution *solution = new Solution();
TreeNode *a = new TreeNode(1);
TreeNode *b = new TreeNode(2);
TreeNode *c = new TreeNode(3);
a->left = nullptr;
a->right = b;
b->left = c;
b->right = nullptr;
c->left = nullptr;
c->right = nullptr;
TreeNode *root = a;
vector<int> ret = solution->postorderTraversal(root);
for (int i = 0; i < ret.size(); i++) {
printf("%d ", ret[i]);
}
printf("\n");
return 0;
}
- Python代码
# -*- coding: utf-8 -*-
from typing import List, Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def __init__(self):
pass
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if None == root:
return []
ret: List[int] = []
s1: List[TreeNode] = [] # 数据栈,存储相关节点的数据,即递归过程中的局部变量。
s2: List[int] = [] # 程序状态栈,根据当前状态判断采取什么操作。如记录当前节点压入了左子树还是右子树。0:压入左子树,1:压入右子树,2:输出根节点的值。
s1.append(root) # 初始化:将根节点压入数据栈中。
s2.append(0) # 初始化:当前根节点对应的操作为压入左子树(即遍历左子树)。
# 从根节点开始遍历,遍历左子树即将左子树压入数据栈,遍历右子树即将右子树压入数据栈,遍历根节点即输出根节点的值。
while s1:
# 获取当前根节点的操作状态,并弹出当前节点的操作状态。
status = s2.pop()
# 对当前节点的具体操作
if 0 == status: # 第一步:遍历当前根节点的左子树
s2.append(1) # 当前根节点的状态码由0转为1,即下一步遍历当前根节点的右节点
if s1[-1].left: # 当前根节点的左节点存在。
s1.append(s1[-1].left) # 将当前根节点的左节点压入数据栈。
s2.append(0) # 将操作状态压入栈,0:遍历左节点。
elif 1 == status: # 第二步:遍历当前根节点的右子树
s2.append(2) # 当前根节点的状态码由1转为2,即下一步输出当前根节点的值
if s1[-1].right:
s1.append(s1[-1].right)
s2.append(0)
elif 2 == status: # 第三步:遍历根节点,输出根节点的值,并弹出根节点
ret.append(s1.pop().val)
return ret
def main():
a: TreeNode = TreeNode(1)
b: TreeNode = TreeNode(2)
c: TreeNode = TreeNode(3)
a.left = None
a.right = b
b.left = c
b.right = None
c.left = None
c.right = None
root: TreeNode = a
solution = Solution()
print(solution.postorderTraversal(root))
if __name__ == "__main__":
main()
说明
- 对应LeetCode第145题。
- 链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/