中序遍历 前序遍历 后序遍历 编程题_力扣(LeetCode)二叉树的前序、中序、后序遍历...

94. 二叉树的中序遍历

144. 二叉树的前序遍历

145. 二叉树的后序遍历

给定一个二叉树,返回它的前序、中序、后序 遍历。

示例:

输入: [1,null,2,3]

b9e41a6f130d81e29f5ae09952b188c7.png

前序输出: [1,2,3]

中序输出: [1,3,2]

后序输出: [3,2,1]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

来源:力扣(LeetCode)

链接:二叉树的中序遍历 - 力扣(LeetCode)

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


题目分析:

树的遍历方式主要有2种,深度优先遍历和广度优先遍历,广度遍历主要为层级遍历,而深度遍历主要分前序遍历、中序遍历、后序遍历,这3种遍历说的前序、中序和后序是指父节点,顺序如下,切莫理解为前序先遍历左节点,后序先遍历右节点。

前序遍历,父节点先遍历,遍历顺序为:父节点-》左节点-》右节点

中序遍历,父节点中间遍历,遍历顺序为:左节点-》父节点-》右节点

后序遍历,父节点后遍历,遍历顺序为:左节点-》右节点-》父节点

具体的解法相信只要学习过数据结构,都会的递归遍历,代码非常简单。

解法一:递归遍历

由于给的案例模板里面的方法带出参,所以我们需要自己写一个递归函数,把list作为入参传到递归函数中。

public List<Integer> preorderTraversal(TreeNode root);
public List<Integer> inorderTraversal(TreeNode root);
public List<Integer> postorderTraversal(TreeNode root);

定义树节点:

class TreeNode {
  int val;
  TreeNode left;
  TreeNode right;

  TreeNode(int x) {
    val = x;
  }
}

递归代码如下:

1、前序遍历

/**
 * 二叉树的前序遍历
 * @param root
 * @return
 */
public List<Integer> preorderTraversal(TreeNode root) {
  List<Integer> res = new ArrayList<>();
  preorderTraversal(root,res);
  return res;
  
}

/**
 * 前序遍历递归函数
 * @param root
 * @param res
 */
private void preorderTraversal(TreeNode root, List<Integer> res) {
  if(root != null){
    res.add(root.val);
    preorderTraversal(root.left, res);
    preorderTraversal(root.right,res);
  }
  
}

2、中序遍历

/**
 * 中序遍历,先遍历左节点,后中节点,后右节点
 * 
 * @param root
 * @return
 */
public static List<Integer> inorderTraversal(TreeNode root) {

  List<Integer> list = new ArrayList<>();
  inorderTraversal(root, list);

  return list;

}

/**
 * 递归函数
 * 
 * @param root
 * @param list
 */
private static void inorderTraversal(TreeNode root, List<Integer> list) {
  if (root != null) {
    inorderTraversal(root.left, list);
    list.add(root.val);
    inorderTraversal(root.right, list);
  }
}

3、后序遍历

/**
 * 二叉树的后序遍历
 * @param root
 * @return
 */
public List<Integer> postorderTraversal(TreeNode root) {
  List<Integer> res = new ArrayList<>();
  // 递归遍历
  postorderTraversal(root,res);
  return res;
}

/**
 * 后序遍历递归函数
 * @param root
 * @param res
 */
private void postorderTraversal(TreeNode root, List<Integer> res) {
 
  if(root!=null){
    // 先遍历左节点
    postorderTraversal(root.left,res);
    // 遍历右节点
    postorderTraversal(root.right,res);
    // 遍历父节点
    res.add(root.val);
  }
  
}

复杂度分析:

时间复杂度:O(n)

空间复杂度:O(n)

解法二:栈遍历

学过jvm的同学都知道,没学过也没关系,记住结论就行,java中所有方法调用都保存在栈中,而递归就是不停的调用方法,所以递归方法调用多少次,每次入参是什么等都保存在栈中,只不过是系统帮我们实现了。当然,我们自己也可以用栈去遍历树而不适用递归方法。所有的递归方法都可以用栈实现哦。

1、前序遍历

/**
 * 二叉树的前序遍历-栈
 * @param root
 * @return
 */
public List<Integer> preorderTraversal(TreeNode root) {
  List<Integer> res = new ArrayList<>();
  // 申请一个栈空间,保存节点
  Stack<TreeNode> stack = new Stack<>();
  TreeNode curr = root;
  
  while(curr != null || !stack.isEmpty()){
    // 当前节点的左节点深度遍历
    while(curr!=null){
      res.add(curr.val);
      stack.push(curr);
      curr = curr.left;
    }
    // 当前节点的左节点访问完毕,访问右节点,对右节点的左节点继续深度遍历
    curr = stack.pop();
    curr = curr.right;
    
  }
  
  return res;
}

2、中序遍历

public List<Integer> inorderTraversal(TreeNode root) {

  // 申请一个栈空间,保存节点
  Stack<TreeNode> stack = new Stack<>();
  List<Integer> res = new ArrayList<>();

  // 定义一个指针,指向根节点
  TreeNode curr = root;
  while (curr != null || !stack.isEmpty()) {
    // 每指向一个节点,把该节点push到栈中,且将左节点push到栈中
    while (curr != null) {
      stack.push(curr);
      curr = curr.left;
    }
    // 左节点不存在,因为是中序遍历,栈中最后一个元素出栈并访问
    curr = stack.pop();
    res.add(curr.val);
    // 指针指向右节点,开始下一个循环,访问该右节点的左节点
    curr = curr.right;
  }
  return res;
}

3、后序遍历,在leetcode中,后序遍历被定义为困难级别,当然,递归算法不可能是困难级别,定义困难的主要原因是利用栈的迭代算法。

从前面的算法中我们可以看出:前序的算法是 父-》左-》右,后序的算法顺序是 左-》右-》父,而在迭代算法中最后访问父节点实现起来比较困难,此时我们可以转换一下思路,我们将后序算法的顺序反向计算,即 左《-右《-父,先遍历父节点,再遍历右节点,再遍历左节点,将遍历结果反向输出,或者保存的时候在链表的最前端保存,同样可以达到后序遍历的效果,总结就是:用前序遍历的算法实现后序遍历。

f77fcd428cedc3e1a5a08ef32d1d9266.png

具体的代码在前序遍历的技术上略作修改即可,具体代码如下:

/**
 * 二叉树的后序遍历-栈
 * @param root
 * @return
 */
public List<Integer> postorderTraversal3(TreeNode root) {
  LinkedList<Integer> res = new LinkedList<>();
  // 定义一个栈
  Stack<TreeNode> stack = new Stack<>();
  TreeNode curr = root;
  
  while(curr != null || !stack.isEmpty()){
    // 当前节点的右节点深度遍历
    while(curr!=null){
      res.addFirst(curr.val);
      stack.push(curr);
      curr = curr.right;
    }
    // 当前节点的左节点访问完毕,访问右节点,对右节点的左节点继续深度遍历
    curr = stack.pop();
    curr = curr.left;
    
  }
  
  return res;
}

复杂度分析:

时间复杂度:O(n)

空间复杂度:O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值