后序遍历
顺序为:左子树->右子树->跟节点
先遍历左子树,然后遍历右子树,最后遍历跟节点,以此轮推,直到遍历所有节点
6
-------------
4 8
-------- -------
2 5 7 9
--------
1 3
如上后序遍历的结果为:1 3 2 5 4 7 9 8 6
后序遍历的逻辑如下:
1.二叉树能直接访问的只有跟节点,所有第一步拿到跟节点6是必须的,但是目的并不是访问它,而是需要获取跟节点6的最深的左子树,通过递归或者迭代,得到左子树节点4,节点4的左子树2,节点2的左子树节点1,节点1即为我们第一个要访问的节点
2.节点1没有子节点,所以节点2左子树上所有节点(1)
已访问,然后回溯到节点1的父节点2(此时不访问节点2的值),父节点2有右子树节点3,则访问右子树节点3
3.节点2 左子树、右子树下的所有节点(1, 3)
都已访问,此时访问节点2,获取节点2的值
4.节点4左子树下的所有节点(1, 3, 2)
都已访问,则访问节点4的右子树节点5
5.节点4 左子树、右子树下的所有节点(1, 3, 2, 5)
都已访问,此时访问节点4,获取节点4的值
6.节点6左子树下的所有节点(1, 3, 2, 5, 4)
都已访问,此时访问节点6的右子树,拿到节点8但是不访问节点8,而是递归或迭代到节点8最深的左子树节点7,访问节点7
7.节点8左子树下所有节点(7)
已访问,则访问节点8的右子树节点9
8.节点8左子树、右子树下的所有节点(7, 9)
都已访问,此时访问节点8,获取节点8的值
9.节点6左子树、右子树下的所有节点(1, 3, 2, 5, 4, 7, 9, 8)
都已访问,此时访问节点6,获取节点6的值
10.至此二叉树的所有节点(1, 3, 2, 5, 4, 7, 9, 8, 6)
都已访问,二叉树后续遍历结束
后序遍历的两种方式:递归实现、迭代实现
递归实现如下
public IList<int> PostorderTraversal(TreeNode root)
{
// 集合存储访问到的节点值
List<int> list = new List<int>();
// 调用递归函数
PostorderTraversal(root, list);
return list;
}
// 递归实现
public void PostorderTraversal(TreeNode root, List<int> list)
{
if (null == root)
{
return;
}
// 递归调用左子树
PostorderTraversal(root.left, list);
// 递归调用右子树
PostorderTraversal(root.right, list);
// 将节点的值存储到集合中
list.Add(root.val);
}
迭代实现如下
// 迭代实现
public Stack<int> PostorderTraversal3(TreeNode root)
{
// 下面使用两个栈Stack结构
// 将节点按照 跟->左->右 次序放入栈 stack
// 然后将节点从栈stack 中出栈,放入栈resultStack
// 栈resultStack即为我们需要的结果
// 利用栈存储访问到的节点值
// 我们需要得到的顺序为 左->右->跟
// 如果我们按照 跟->右->左 的方式将节点存入栈中
// 则依次将结果出栈得到的结果即为我们需要的次序: 左->右->跟
Stack<int> resultStack = new Stack<int>();
if (null == root)
{
return resultStack;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
// 将跟节点入栈
stack.Push(root);
while (stack.Count > 0)
{
// 节点出栈
TreeNode node = stack.Pop();
// 将 stack 出栈的节点值存入 resultStack
resultStack.Push(node.val);
// 如果左子树不为空,则将左子树入栈stack
if (null != node.left)
{
stack.Push(node.left);
}
// 如果右子树不为空,则将右子树入栈stack
if (null != node.right)
{
stack.Push(node.right);
}
}
return resultStack;
}
至此二叉树后续遍历原理以及实现均已奉上