刷题笔记:树的前序、中序、后序遍历

在此之前,我们定义二叉树的数据结构如下:


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;

    }


猜你喜欢

转载自blog.csdn.net/qq_35531985/article/details/109403122