树的前序、中序遍历的递归和非递归实现

前言

我们知道,树是一种非常重要的数据结构,在各种竞赛和各大企业笔试题中,关于树,特别是二叉树的题目出现频率都很高。

今天我们来掌握二叉树的前序、中序遍历,并且给出递归和非递归两种实现。

用节点表示树

package org.lanqiao.algo;

public class TreeNode<T> {
  public T val ;
  public TreeNode<T> left = null;
  public TreeNode<T> right = null;

  public TreeNode(T val) {
    this.val = val;
  }
}

中序遍历

所谓中序遍历,是根节点居中出现的一种遍历方式,遵循左-根-右的原则。

递归形式:

public static void inorderIter(TreeNode node, Consumer consumer) {
    if (null != node.left)
      inorderIter(node.left, consumer);
    consumer.accept(node.val);
    if (null != node.right)
      inorderIter(node.right, consumer);
  }

比较复杂的是非递归形式,非递归形式要借用栈这种结构:

  • 先顺着根节点把所有左支路的节点压入栈中,这时,栈顶是最左的叶子节点
  • 接下来开始弹弹弹
    • 首先弹出的肯定是最左叶子
    • 弹出来的对象供消费
    • 重点来了,如果弹出的节点有右孩子,就暂停弹出,应该从这个右孩子开始回到步骤起点,把右孩子作为起点重新来一轮
  public static void inorderIterNoRecursion(TreeNode node, Consumer consumer) {
    Stack<TreeNode> stack = new Stack<>();
    TreeNode curr = node;
    while (curr != null) {
      // 顺着当前节点将左支路的节点从上往下加入栈中,最后:最左叶子节点在栈顶
      while (curr != null) {
        stack.add(curr);
        curr = curr.left;
      }
      //接下来开始弹弹弹,首先弹出的肯定是最左叶子
      while (!stack.isEmpty()) {
        TreeNode pop = stack.pop();
        consumer.accept(pop.val);// 弹出来的对象供消费
        //重点来了,如果弹出的节点有右孩子,就暂停弹出,应该从右孩子开始回到外层循环的起点,把右孩子作为起点重新来一轮
        if (pop.right != null) {
          curr = pop.right;
          break;
        }
      }

    }
  }

前序遍历

前序遍历,是根节点靠前出现的一种形式,遵循根-左-右的原则。

递归形式:

  public static void preIter(TreeNode<Integer> node) {
    System.out.print(node.val + "\t");
    if (null != node.left)
      preIter(node.left);
    if (null != node.right)
      preIter(node.right);
  }

非递归形式:

  • 根节点入栈
  • 循环开始
    • 弹出栈顶
    • 栈顶的右孩子入栈
    • 栈顶的左孩子入栈
    • 栈空结束循环
public static void preIterNoRecursion(TreeNode<Integer> node) {
    TreeNode curr = node;
    Stack<TreeNode> stack = new Stack<>();
    stack.add(curr);
    while (!stack.isEmpty()) {
      //弹出栈顶
      TreeNode pop = stack.pop();
      System.out.print(pop.val + "\t");
      if (pop.right != null) {
        stack.add(pop.right);
      }
      if (pop.left != null) {
        stack.add(pop.left);
      }
    }
  }

牢记这些代码,一些关于树遍历的变种题,会比较好解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值