风也温柔

计算机科学知识库

【技术】递归算法的三个要素(一)——递归递归

  二叉树遍历分为前序遍历、中序遍历、后序遍历、分层遍历

  它的实现可以使用递归或迭代方法。

  递归遍历

  这里帮助你识别递归算法的三个要素。每次写递归,都按照这三个要素来写,这样可以保证大家都能写出正确的递归算法!

  确定递归函数的参数和返回值:确定递归过程中需要处理哪些参数,然后把这个参数加到递归函数中,还要明确每个递归的返回值是什么,确定递归的返回类型递归函数。确定终止条件:递归算法写好后,在运行的时候,经常会遇到栈溢出错误,即没有写完终止条件或者写错了终止条件。操作系统也使用栈结构来存储每一层递归的信息。,如果递归不终止二叉树遍历算法 java,操作系统的内存栈必然会溢出。确定单级递归的逻辑:确定每个递归级别需要处理的信息。在这里,它会反复调用自己来实现递归过程。

  下面是一个前序遍历的例子:

  确定递归函数的参数和返回值:因为需要打印出前序遍历节点的值,所以需要在参数中传入List存储节点的值。除此之外,不需要处理任何数据或返回值,所以递归函数的返回类型为void,代码如下:

   private void preOrder(List list, TreeNode root)

  确定终止条件:在递归的过程中,怎样才能认为递归已经结束?当然,当前遍历的节点是空的,那么这一层的递归就要结束了,所以如果当前遍历的节点是空的,直接就可以了,代码如下:

   if(root==null) return;

  确定单级递归的逻辑:前序遍历是中左的顺序,所以单级递归的逻辑是先取中间节点的值。代码如下:

   if(root!=null) list.add(root.val);//中

     if(root.left!=null) preOrder(list,root.left);//左
     if(root.right!=null) preOrder(list,root.right);//右

  单级递归的逻辑按照中左顺序进行处理,这样二叉树的前序遍历就基本完成了。我们来看看完整的代码:

   package 力扣;

    import java.util.ArrayList;
    import java.util.List;
    /**
     * @author yyq
     * @create 2022-04-06 10:30
     * 二叉树的前序遍历
     * 实现方式:
     *          1.递归遍历
     *          2.迭代遍历
     *
     */
    public class leetcode144 {
        public List preorderTraversal(TreeNode root) {
            List list = new ArrayList();
            if(root!=null)
            preOrder(list,root);
            return list;
        }
        private void preOrder(List list, TreeNode root) {
            if(root==null) return;
            if(root!=null) list.add(root.val);
            if(root.left!=null) preOrder(list,root.left);
            if(root.right!=null) preOrder(list,root.right);
        }
    }
    class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode() {}
        TreeNode(int val) { this.val = val; }
        TreeNode(int val, TreeNode left, TreeNode right) {
              this.val = val;
              this.left = left;
             this.right = right;
         }
      }

  由于二叉树的递归遍历类似,后两种实现在此不再赘述。

  迭代遍历 (迭代法)

  前序遍历在中间和左侧。每次先处理中间节点【技术】递归算法的三个要素(一)——递归递归
,然后先将根节点入栈,再将右孩子入栈,再将左孩子入栈。

  为什么要先添加右孩子二叉树遍历算法 java,然后再添加左孩子?因为这是出栈时的中左顺序。

  

  (注意代码中的空节点不会被压入栈中)

   public List preorderIterative(TreeNode root) {

            List list = new ArrayList();
            Stack stack=new Stack();
            if(root!=null) stack.push(root);
            else return list;
            while (!stack.isEmpty()){
                TreeNode pop = stack.pop();
                list.add(pop.val);
                if(pop.right!=null)
                stack.push(pop.right);
                if(pop.left!=null)
                stack.push(pop.left);
            }
            return list;
        }

  中序遍历(迭代法)

  为了解释清楚,我解释一下,在刚才的迭代过程中,我们其实有两个操作:

  处理:将元素放入列表集合访问:遍历节点

  分析一下刚才写的前序遍历代码为什么不能和中序遍历一样使用,因为前序遍历的顺序是中左,最先访问的元素是中间节点,要遍历的元素被处理的也是中间节点,所以只能写刚才。代码比较简洁,因为要访问的元素和要处理的元素顺序一致,都是中间节点。

  然后看中序遍历。中序遍历是左、中、右。首先访问二叉树顶部的节点,然后逐层访问,直到到达树的左侧底部,然后开始处理节点(即在Put中的值节点放入数组中),导致处理顺序和访问顺序不一致。

  那么,在使用迭代的方式编写中序遍历时,需要使用指针遍历来帮助访问节点,而栈则用于处理节点上的元素。

  动画如下:

  

   public List inorderIterative(TreeNode root) {

            List list=new ArrayList();
            Stack stack=new Stack();
            if(root == null) return list;
            TreeNode temp=root;
            stack.push(root);
            while (!stack.isEmpty()){
                if(temp.left!=null){
                    stack.push(temp.left);
                    temp=temp.left;
                }else {
                    TreeNode pop = stack.pop();
                    list.add(pop.val);
                    if(pop.right!=null){
                        temp= pop.right;
                        stack.push(pop.right);
                    }
                }
            }
            return list;
        }

  后序遍历(迭代法)

  让我们看一下后序遍历。前序遍历是中间左右,后续遍历是左右中间。那么我们只需要调整前序遍历的代码顺序,变成中右左遍历顺序,然后将数组倒过来,输出结果。顺序为左右,如下图:

  因此后序遍历只需要对前序遍历的代码稍作修改即可。代码如下:

   // 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果

    class Solution {
        public List postorderTraversal(TreeNode root) {
            List result = new ArrayList();
            if (root == null){
                return result;
            }
            Stack stack = new Stack();
            stack.push(root);
            while (!stack.isEmpty()){
                TreeNode node = stack.pop();
                result.add(node.val);
                if (node.left != null){
                    stack.push(node.left);
                }
                if (node.right != null){
                    stack.push(node.right);
                }
            }
            Collections.reverse(result);
            return result;
        }
    }

  文章来源:https://blog.csdn.net/weixin_40422192/article/details/123990643