二叉树遍历(递归、迭代、左侧链思路迭代)

二叉树遍历

GitHub源码

什么是遍历?

按照某种特定的规则、次序依次对每个节点进行访问。

为什么要遍历?

可以将二叉树这个半线性化的结构转化为线性结构,对结构进行简化,更方便。

有哪些遍历方式?

  • 先序
  • 中序
  • 后序
  • 层次

树节点

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

    public TreeNode() {}

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

先序

递归实现

public static void pre(TreeNode head) {
    if (head == null) {
        return;
    }
    visit(head);
    pre(head.left);
    pre(head.right);
}
  • 一个退化情况处理(递归基)
  • 递归实现左子树和右子树遍历(注意这个是尾递归)

迭代实现1

public static void preIt(TreeNode head) {
    Deque<TreeNode> stack = new ArrayDeque<>();
    stack.push(head);
    while (!stack.isEmpty()) {
        // 先打印根节点
        TreeNode node = stack.pop();
        visit(node);

        // 两个孩子依次入栈
        // 因为先进后出,所以要先进右孩子
        if (node.right != null) {
            stack.push(node.right);
        }
        if (node.left != null) {
            stack.push(node.left);
        }
    }
}

迭代实现2(左侧链实现)

public static void preLeftBranch1(TreeNode head) {
    Deque<TreeNode> stack = new ArrayDeque<>();
    while (head != null) {  // 沿着左侧链下行
        visit(head);
        if (head.right != null) {
            stack.push(head.right);
        }
        head = head.left;
        // 当左侧链到底,沿着右侧链上行
        if (head == null && !stack.isEmpty()) {
            head = stack.pop();
        }
    }
}

迭代实现3(左侧链实现,清晰版)

public static void preLeftBranch2(TreeNode head) {
    Deque<TreeNode> stack = new ArrayDeque<>();
    while (true) {  // 不断地
        visitAloneLeftBranch(head, stack);
        if (stack.isEmpty()) {
            break;
        }
        head = stack.pop();
    }
}

// 沿着左侧链访问
private static void visitAloneLeftBranch(TreeNode head, Deque<TreeNode> stack) {
    while (head != null) {
        visit(head);
        if (head.right != null) {
            stack.push(head.right);
        }
        head = head.left;
    }
}

中序

递归实现

public static void in(TreeNode head) {
    if (head == null) {
        return;
    }
    in(head.left);
    visit(head);
    in(head.right);
}

迭代实现1

public static void inIt(TreeNode head) {
    Deque<TreeNode> stack = new ArrayDeque<>();
    if (head != null) {
        while (!stack.isEmpty() || head != null) {
            if (head != null) { // 先把所有的左子全压入栈中
                stack.push(head);
                head = head.left;
            } else {    // 当压不动了的时候(即head此时为空),则开始出栈并打印,然后来到右孩子处
                head = stack.pop();
                visit(head);
                head = head.right;
            }
        }
    }
}

迭代实现2

public static void inLeftBranch(TreeNode head) {
    Deque<TreeNode> stack1 = new ArrayDeque<>();
    Deque<TreeNode> stack2 = new ArrayDeque<>();
    while (head != null) {
        if (head.right != null) {
            stack2.push(head.right);
        }
        stack1.push(head);
        head = head.left;
        if (head == null) {
            while (!stack1.isEmpty()) {
                TreeNode node = stack1.pop();
                visit(node);
            }
            if (!stack2.isEmpty()) {
                head = stack2.pop();
            }
        }
    }
}

后序遍历

递归实现

public static void post(TreeNode head) {
    if (head == null) {
        return;
    }
    post(head.left);
    post(head.right);
    visit(head);
}

迭代实现1

public static void postIt(TreeNode head) {
    Deque<TreeNode> stack = new ArrayDeque<>();
    Deque<Integer> turnStack = new ArrayDeque<>();
    stack.push(head);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();

        // 这里只是进入反转栈,而不是打印
        turnStack.push(node.val);

        // 先序是:center left right
        // 那么将下面步骤反转可以获得:center right left
        // 再将这个翻转可获得:left right center 即为后序遍历
        if (node.left != null) {
            stack.push(node.left);
        }
        if (node.right != null) {
            stack.push(node.right);
        }
    }

    // 然后依次取出打印反转栈
    while (!turnStack.isEmpty()) {
        Integer val = turnStack.pop();
        System.out.print(val + " ");
    }
}

迭代实现2

public static void postItOneStack(TreeNode head) {
    // p追踪每次打印的q,q则按顺序跳动
    TreeNode p = head, q = head;
    Deque<TreeNode> stack = new ArrayDeque<>();
    stack.push(head);
    while (!stack.isEmpty()) {
        // 注意如果q要继续往左需要满足上一次没有遍历到左而且上一次没有遍历到右
        // 特别需要注意上一次没有遍历到右的情况
        if (q.left != null && p != q.left && p != q.right) {
            stack.push(q);
            q = q.left;
        } else if (q.right != null && p != q.right) {
            stack.push(q);
            q = q.right;
        } else {
            System.out.print(q.val + " ");
            p = q;
            q = stack.pop();
        }
    }
}

层次遍历

public static void level(TreeNode head) {
    Deque<TreeNode> queue = new ArrayDeque<>();
    queue.offer(head);
    while (!queue.isEmpty()) {
        TreeNode node = queue.poll();
        visit(node);
        if (node.left != null) {
            queue.offer(node.left);
        }
        if (node.right != null) {
            queue.offer(node.right);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值