作者: 奉先 | 来源:发表于2021-09-25 08:22 被阅读0次

    1. 二叉树的遍历

    二叉树的遍历可以有三种 : 先序、 中序、 后序遍历 。先序是根左右 ,中序是左根右 ,后序是左右根。 这三种遍历方式可以使用递归实现,也可以不用递归(自己来压栈代替系统压栈)。

    1.1 递归实现

    为了记忆方便,可以统一使用 “递归序”来实现三种次序的遍历 。 看如下的代码

    public class Traverse {
        public void myTraverse(TreeNode head){
            //process1
            if(head == null ) return;
            //process1
            myTraverse( head.left);
            //process2
            //process2
            myTraverse( head.right);
            //process3
            //process3
    
        }
    }
    

    如果在process1之间,执行代码就是先序遍历,在process2之间,执行代码就是中序遍历,在process3之间,执行代码就是中序遍历,这样代码就非常容易实现了。下面是按照递归序改造的先序遍历在leetcode上执行,因为不是void型返回结果,而是把遍历结果插入到一个list中,所以代码中带了一个list型的参数,但是不影响主体。

    class Solution {
    
        //通过递归序完成先序遍历
        public List<Integer> preorderTraversal(TreeNode root) {
            List<Integer> outPut = new ArrayList<>() ; 
            Traversal(root,outPut) ;
            return outPut ; 
        }
    
        public void Traversal(TreeNode root, List<Integer> outPut){
            if(root == null) return ;
            outPut.add(root.val) ;
            Traversal(root.left, outPut) ;
            Traversal(root.right, outPut) ;
        }
    
    }
    

    1.2 非递归实现 :

    非递归实现三种遍历方式,使用额外栈来实现,这样容易记忆 。

    1.2.1 先序遍历 :

    先序遍历使用栈,要记住下边几个步骤 :

    1.初始化将树的根节点压栈 ;
    2.从栈中弹出一个节点 ;
    3.开始做遍历操作(例如:打印等等)
    4.把这个弹出的节点的子树压栈(先右后左,如果有的话)
    5.循环执行 2~3 步骤。

    下面是使用 栈完成的非递归前序遍历 :

        //通过非递归序完成先序遍历
        public List<Integer> preorderTraversal(TreeNode root) {
            List<Integer> outPut = new ArrayList<>() ;
            if(root != null){
                Stack<TreeNode> usStack = new Stack() ;
                usStack.push(root);
                while(!usStack.isEmpty()){
                    TreeNode cp = usStack.pop();
                    outPut.add(cp.val) ;
                    if(cp.right != null) usStack.push(cp.right);
                    if(cp.left != null) usStack.push(cp.left);
                }
    
            }
            return outPut;
        }
    

    1.2.2 后序遍历 :

    上边前序遍历,使用了一个栈,压栈顺序是根、右、左 ,输出顺序是 根、左、右(也就是前序遍历)。这时,在压栈时,如果我先压左再压右,那么输出顺序就变成了 根、右、 左。
    这时,我再使用一个辅助收集栈,输出时候不打印,而是放入收集栈,最后再输出时,就变成了后序遍历了。 相比于前序遍历得到立即打印,这个就变成了都压栈完后,一起打印就得到了后序遍历了。
    这样流程就梳理为下边的样子 :

    1.初始化将树的根节点压原始栈 ;
    2.从原始栈中弹出一个节点,记为cur ;
    3.cur压入收集栈
    4.把这个cur的子树压入原始栈(先左后右,如果有的话)
    5.循环执行 2~4 步骤。
    6.将收集栈统一打印。

    下边是后序遍历的非递归实现 :

    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> outPut = new ArrayList<>() ;
            if(root != null){
                Stack<TreeNode> oriStack = new Stack() ;
                Stack<TreeNode> collectStack = new Stack() ;
                oriStack.push(root);
                while(!oriStack.isEmpty()){
                    TreeNode curr = oriStack.pop();
                    collectStack.push(curr);
                    //原始栈的压栈次序是先左后右,与先序遍历不一样
                    if(curr.left != null) oriStack.push(curr.left);
                    if(curr.right != null) oriStack.push(curr.right);
                }
                while (!collectStack.isEmpty()){
                    outPut.add(collectStack.pop().val);
                }
            }
            return outPut;
        }
    }
    

    1.2.3 中序遍历 :

    中序遍历的算法有所不同 ,使用一个栈就可以完成。 流程如下 :

    1.初始化将树的根节点压栈 ;
    2.对于每一棵子树,左边界依次压栈,直到压到为NULL为止。
    3.弹出栈顶节点,弹出时打印。
    4.对弹出节点的右子树重复,2-3过程。

    下面是 中序遍历的java代码实现(非递归):

    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> outPut = new ArrayList<>();
            if (root != null) {
                Stack<TreeNode> oriStack = new Stack();
                while(!oriStack.isEmpty() || root !=null){
                    if(root != null){
                        oriStack.push(root) ;
                        root = root.left ;
                    }
                    else
                    {
                        root = oriStack.pop() ;
                        outPut.add(root.val) ;
                        root = root.right ;
                    }
                }
            }
            return outPut ;
        }
    }
    

    2. 搜索二叉树

    如何判断一棵树是搜索二叉树 ,要完成这个问题,首先需要了解什么是搜索二叉树 ?

    对于一棵搜索二叉树而言,每一个节点的左子树都比右子树小 。也就是说 左子树节点 < 根节点 < 右子树节点。经典的搜索二叉树中没有重复值的节点。

    其实比较简单,只要做“中序遍历” 后,得到的序列是单调上升,即可表示是一棵搜索二叉树。

    相关文章

      网友评论

        本文标题:

        本文链接:https://www.haomeiwen.com/subject/pwotnltx.html