树 先序遍历 中序遍历 后序遍历

 写之前先看作用:

先序遍历:在第一次遍历到节点时就执行操作,一般只是想遍历执行操作(或输出结果)可选用先序遍历;
中序遍历:对于二分搜索树,中序遍历的操作顺序(或输出结果顺序)是符合从小到大(或从大到小)顺序的,故要遍历输出排序好的结果需要使用中序遍历
后序遍历:后续遍历的特点是执行操作时,肯定已经遍历过该节点的左右子节点,故适用于要进行破坏性操作的情况,比如删除所有节点

 

先序:中 左 右的顺序(先访问根节点,先序遍历左子树,先序遍历右子树

中序:左 中 右的顺序

后序:左 右 中的顺序

遍历过程相同,只是访问各个节点的时机不同

 

先序遍历

 

 递归实现:

    public static void preOrderRecur(TreeNode treeNode)
    {
        if (treeNode==null)
        {
            return;
        }
        System.out.println(treeNode.val);
        preOrderRecur(treeNode.left);
        preOrderRecur(treeNode.right);
    }

够简单,需要注意终止条件。否则会空指针异常。

 

非递归实现(自己维护一个栈):

public static void preOrder(TreeNode treeNode)
    {
        if(treeNode==null)
        {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();//注意泛型
        stack.push(treeNode);
        while (stack.size()!=0)
        {
            treeNode=stack.pop();
            System.out.println(treeNode.val + " ");
            if(treeNode.right!=null)//注意不为null的条件,否则出栈会空指针
            {
                stack.push(treeNode.right);//由于先处理左子树,后处理右子树,所以压栈顺序反过来就行
            }
            if(treeNode.left!=null)
            {
                stack.push(treeNode.left);
            }

        }
    }

这个迭代写的有点像递归了。。。

 

中序遍历

 

 

 

递归写法,真的爽,不用考虑具体的压栈过程,关注什么时候结束和递归逻辑就行

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        parse(root,list); 
        return list;       
    }

    public void parse(TreeNode root,List<Integer> list)
    {
        if(root==null)
        {
            return;
        }
        parse(root.left,list);
        list.add(root.val);
        parse(root.right,list);
    }
}

 

非递归写法:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        Stack<TreeNode> stack=new Stack<>();
        List<Integer> list=new ArrayList<>();
        while(stack.size()>0||root!=null)
        {
            while(root!=null)//处理root节点,去往最左侧,出循环后栈顶为优先级最高节点
            {
                stack.push(root);
                root=root.left;
            }
            TreeNode outNode=stack.pop();//到这里保证左侧已经没有东西了,outnode代表目前全树优先级最高的节点
            list.add(outNode.val);//处理“中”
            if(outNode.right!=null)//处理“右”,这一步加上去往最左能保证右子树被处理完
            {
                root=outNode.right;
            }
        } 
        return list;
    }   
}
  • root是要处理的节点,当root不为null时,还没有找到最高优先级的节点,当root为null时,最高优先级节点在栈顶,且这个最高优先级节点的父亲在栈的第二位
  • 处理最高优先级节点的办法是,弹出栈,输出最高优先级节点,处理右子树(即把root设置为其右孩子)
  • 还是有点绕的。。。

 

后序遍历

 

 

递归写法,差不多

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        postOrder(root,list);
        return list;
    }

    public void postOrder(TreeNode root,List<Integer> list)
    {
        if(root==null)
        {return;}
        postOrder(root.left,list);
        postOrder(root.right,list);
        list.add(root.val);
    }
}

非递归写法有两种

第一种:双栈法,前序遍历不是中左右,改变一下压栈顺序就成了中右左,倒序过来就是左右中。

倒序使用第二个栈就能实现,记录下来出栈的节点就可以

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        if(root==null)
        {return list;}
        Stack<TreeNode> stackReverse=new Stack<TreeNode>();
        Stack<TreeNode> stackResult=new Stack<TreeNode>();
        stackReverse.push(root);
        while(stackReverse.size()>0)
        {
            root=stackReverse.pop();
            stackResult.add(root);
            if(root.left!=null)
            {stackReverse.push(root.left);}
            if(root.right!=null)
            {stackReverse.push(root.right);}
        }
        while(stackResult.size()>0)
        {
            list.add(stackResult.pop().val);
        }
        return list;
    }
}

 第二种,硬写呗

和中序遍历有点像,先要找优先级最高的节点root,往左探

当root为null时,cur=stack.pop,但是此时优先级更高的不是cur而是cur.right

所以加入cur.right不为null,肯定要先处理右侧节点,cur要先放回栈

为了到时右侧节点被处理完了,cur再出栈时能知道,所以加了一个pre(因为cur.right处理完肯定下一个就是cur)

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        if(root==null)
        {return list;}
        Stack<TreeNode> stack=new Stack<TreeNode>();
        TreeNode pre=null;
        while(stack.size()>0||root!=null)
        {
            while(root!=null)
            {
                stack.push(root);
                root=root.left;
            }
            TreeNode cur=stack.pop();
            if(cur.right==null||pre==cur.right)
            {
                list.add(cur.val);
                pre=cur;
            }
            else
            {
                stack.push(cur);
                root=cur.right;
            }
        }
        return list;
    }
}

 

posted @ 2020-12-04 20:18  将来的事  阅读(925)  评论(0编辑  收藏  举报