在此之前,我们定义二叉树的数据结构如下:
class TreeNode//节点结构
{
int value;
List<TreeNode> children=new ArrayList<>();
TreeNode left;
TreeNode right;
TreeNode(int value)
{
this.value = value;
}
}
//主函数
public class main {
public static List<Integer> res=new ArrayList<>();
public static void main(String[] args) {
//以下为前序后续遍历N叉树建树的过程
TreeNode[] node = new TreeNode[10];//以数组形式生成一棵完全二叉树
for(int i = 0; i < 10; i++)
{
node[i] = new TreeNode(i);
}
//建树
for(int i = 0; i < 10; i++)
{
if(i*2+1 < 10)
node[i].children.add(node[i*2+1]);
if(i*2+2 < 10)
node[i].children.add(node[i*2+2]);
}
// 注释部分适用于中序遍历二叉树创建树结构
// TreeNode[] node = new TreeNode[10];
// for(int i = 0; i < 10; i++)
// {
// node[i] = new TreeNode(i);
// }
// for(int i = 0; i < 10; i++)
// {
// if(i*2+1 < 10)
// node[i].left = node[i*2+1];
// if(i*2+2 < 10)
// node[i].right = node[i*2+2];
// }
// System.out.println("前序递归");
// PreOrder.preOrderRecursion(node[0],res);
// System.out.println(res.toString());
//
// System.out.println("前序非递归");
// List<Integer> resultPre=PreOrder.preOrder(node[0]);
// System.out.println(resultPre.toString());
// System.out.println("中序递归");
// MidOrder.midOrderRecursion(node[0],res);
// System.out.println(res.toString());
//
// System.out.println("中序非递归");
// List<Integer> resultMid=MidOrder.midOrder(node[0]);
// System.out.println(resultMid.toString());
System.out.println("后序递归");
LateOrder.postOrderRe(node[0],res);
System.out.println(res.toString());
System.out.println("后序非递归");
List<Integer> resultMid=LateOrder.postOrder(node[0]);
System.out.println(resultMid.toString());
}
}
前序遍历
前序遍历又称先根遍历,遍历顺序是根->左->右。遍历步骤是:
若 二叉树为空则结束返回,否则:
(1)访问根结点。
(2)前序遍历左子树 。
(3)前序遍历右子树 。
上图的前序遍历为:ABDECF.
注意:已知后序遍历和中序遍历,就能确定前序遍历。
递归
public static void preOrderRecursion(TreeNode treeNode,List<Integer> res){
List<TreeNode> children=treeNode.children;
res.add(treeNode.value);
for(TreeNode node:children){
if(node!=null){
preOrderRecursion(node,res);
}
}
}
非递归
//非递归,需要依靠栈实现
public static List<Integer> preOrder(TreeNode treeNode){
Stack<TreeNode> stack=new Stack<>();
List<Integer> res=new ArrayList<>();
stack.add(treeNode);
while (!stack.isEmpty()){
TreeNode root=stack.pop();
res.add(root.value);
Collections.reverse(root.children);
for(TreeNode child:root.children){
stack.add(child);
}
}
return res;
}
中序遍历
中序遍历又称中根遍历,遍历顺序是左->根->右。
若二叉树为空则结束返回,
否则:
(1)中序遍历左子树
(2)访问根结点
(3)中序遍历右子树
上图的中序遍历结果为:DBEAFC
递归
public static void midOrderRecursion(TreeNode treeNode, List<Integer> res){
if (treeNode==null)
return;
else{
midOrderRecursion(treeNode.left, res);
res.add(treeNode.value);
midOrderRecursion(treeNode.right, res);
}
}
非递归
//非递归,需要依靠栈实现
public static List<Integer> midOrder(TreeNode treeNode){
Stack<TreeNode> stack=new Stack<>();
List<Integer> res=new ArrayList<>();
while(treeNode != null || !stack.isEmpty()){
while (treeNode!=null){
stack.push(treeNode);
treeNode = treeNode.left;
}
if(!stack.isEmpty()){
treeNode=stack.pop();
res.add(treeNode.value);
treeNode = treeNode.right;
}
}
return res;
}
后续遍历
后续遍历,又称后根遍历。即先输出孩子节点,后输出跟节点,遍历顺序左->右->根。
若二叉树为空则结束返回,
否则:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根结点
递归
public static void postOrderRe(TreeNode treeNode, List<Integer> res)
{
//后序遍历递归实现
if(treeNode == null)
return;
else
{
List<TreeNode> children=treeNode.children;
for(TreeNode node:children){
if(node!=null){
postOrderRe(node,res);
}
}
res.add(treeNode.value);
}
}
非递归
后续遍历的非递归算法与前序遍历的非递归算法很像。我们举个例子:
在后序遍历中,我们会先遍历一个节点的所有子节点,再遍历这个节点本身。例如当前的节点为 u,它的子节点为 v1, v2, v3
时,那么后序遍历的结果为 [children of v1], v1, [children of v2], v2, [children of v3], v3, u
,其中 [children of vk]
表示以 vk
为根节点的子树的后序遍历结果(不包括 vk 本身)。我们将这个结果反转,可以得到 u, v3, [children of v3]', v2, [children of v2]', v1, [children of v1]'
,其中 [a]’ 表示 [a] 的反转。此时我们发现,结果和前序遍历非常类似,只不过前序遍历中对子节点的遍历顺序是 v1, v2, v3
,而这里是 v3, v2, v1
。
因此我们可以使用和 N叉树的前序遍历
相同的方法,使用一个栈来得到后序遍历。我们首先把根节点入栈。当每次我们从栈顶取出一个节点 u
时,就把 u
的所有子节点顺序推入栈中。例如 u
的子节点从左到右为 v1, v2, v3
,那么推入栈的顺序应当为 v1, v2, v3
,这样就保证了下一个遍历到的节点(即 u
的第一个子节点 v3
)出现在栈顶的位置。在遍历结束之后,我们把遍历结果反转,就可以得到后序遍历。(以上参考Leetcode题解)
public static List<Integer> postOrder(TreeNode treeNode)
{
Stack<TreeNode> stack = new Stack<>();
List<Integer> output = new ArrayList<>();
if (treeNode == null) {
return output;
}
stack.add(treeNode);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
output.add(node.value);
for (TreeNode item : node.children) {
if (item != null) {
stack.push(item);
}
}
}
Collections.reverse(output);
return output;
}