10.4力扣题目总结:二叉树的遍历

前言:二叉树有三种遍历:前序,中序,后序.

针对这三种遍历方式,又有算法:递归遍历,迭代遍历.

一.递归遍历

这是代码比较简洁的遍历,但是又不容易理解.不过遇到题目直接按照以下三步骤来:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,以及返回值是什么.

  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。

  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。(摘编自代码随想录)

 其实又想了一下递归,简单理解就是,本质还是函数的相互调用,执行return其实就是返回上一个调用该函数的函数,然后继续往下执行的过程.一直到根节点执行完毕,该程序也执行完毕.

如果还不好理解的话,可以借助二叉树的图,把每一个节点当做一个函数,该节点会调用函数,执行相应的return操作等.

前序,中序,后序的区别就在于遍历的顺序,所以代码都是差不多的,这里就以其中一个为例:

/**
 * Definition for a binary tree node.
 * public 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;
 *     }
 * }
 */
//上面就是定义二叉树的节点的结构
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result=new LinkedList<Integer>();
        traversal(root,result);
        }
        return result;
    }
     public void traversal(TreeNode root,List<Integer> list){
         if(root==null)
         return;
         list.add(root.val);
         traversal(root.left,list);
         traversal(root.right,list);
     }
}

这个是前序遍历的.如果是其他遍历,只需要交换traversal函数里面的最后三行顺序即可.不知道怎么交换的话,可以都试试.

二.迭代遍历

这对我来说是个新东西,因为之前没怎么学.

1.前序遍历:

节点定义和上面是一样的,这里就没写了.


class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result=new LinkedList<Integer>();
        if(root==null)
        return result;
        Stack<TreeNode> stack=new Stack<>();
        //先将根节点压入
        stack.push(root);
        while(!stack.isEmpty()){
           TreeNode node=stack.pop();
           result.add(node.val);
           if(node.right!=null){
            stack.push(node.right);
           }
           if(node.left!=null){
            stack.push(node.left);
           }
        }
        return result;
    }
}

由于栈是"先进后出"的,因此在循环中要先将右节点压入栈.这样才能先让左节点先出栈.

2.中序遍历

中序遍历不能只改一下前序的代码.因为前序遍历时,我们访问的节点顺序和要遍历的数据顺序是一致的,而中序是"左,根,右"的顺序,这和我们代码访问节点的顺序不一致,因此要调整一下.

 

 List<Integer> result=new LinkedList<>();//存放结果用
        Stack<TreeNode> stack=new Stack<>();//新建一个栈用来存结点
        if(root==null)
        return result;//如果是一个空树就直接返回
       TreeNode cur=root;
        while(cur!=null||!stack.isEmpty()){
            if(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }
            else{
               cur=stack.pop();
               result.add(cur.val);
               cur=cur.right;
            }
        }
        return result;

这段代码的巧妙之处就在于:到了叶子结点的时候,它的左子树为空,就让该节点出栈,并将数值加入结果中,并让cur指向右.而右边也为空,那再让元素出栈,此时出栈的就是它的父节点.这就实现了"指针上移",然后又添加父节点的右子树(恰好刚刚没有添加).

针对循环条件来说,因为cur为空时,程序并没有结束,我们希望它继续,所以加一个"栈不为空".

当cur指向根节点时,栈为空,但是它还有右子树.cur不为空,所以还能继续执行.

3.后序遍历

待更新....

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值