刷题笔记5——二叉树

基础知识

  • 什么时候需要用到二叉树的概念?
    • 是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。
    • 是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。

为什么多叉树没有中序位置?
因为二叉树的每个节点只会进行唯一一次左子树切换右子树,而多叉树节点可能有很多子节点,会多次切换子树去遍历,所以多叉树节点没有「唯一」的中序遍历位置。

前序位置的代码在刚刚进入一个二叉树节点的时候执行;

后序位置的代码在将要离开一个二叉树节点的时候执行;

中序位置的代码在一个二叉树节点左子树都遍历完,即将开始遍历右子树的时候执行。

二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的,你只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作。比如快速排序:是个先序排列, 归并排序:是个后序排列,这两个的遍历流程和基本的流程是一样的,关键就在于快排是怎么比较大小的,基准是怎么样的,是如何划分左右子树的等

  • 二叉树题目的递归解法可以分两类思路
    • 第一类是遍历一遍二叉树得出答案(回溯算法核心框架),只需要访问到该节点即可,不需要进行return,回溯法如果用在树结构的话就是dfs
    • 第二类是通过分解问题计算出答案 (动态规划核心框架),动态规划适合于最优子结构问题,即大问题的处理依赖于每个子问题的结果,所以需要return子问题的结果

倒序打印单链表,可以使用递归的概念

刷题笔记5——二叉树_第1张图片

/* 递归遍历单链表,倒序打印链表元素 */
void traverse(ListNode head) {
    if (head == null) {
        return;
    }
    traverse(head.next);
    // 后序位置
    print(head.val);
}

二叉树(就是个复杂的二叉链表)

单链表和数组的遍历可以是迭代的,也可以是递归的,二叉树这种结构无非就是二叉链表,由于没办法简单改写成迭代形式,所以一般说二叉树的遍历框架都是指递归的形式。

void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    // 前序位置
    traverse(root.left);
    // 中序位置
    traverse(root.right);
    // 后序位置
}

/* 迭代遍历数组 */
void traverse(int[] arr) {
    for (int i = 0; i < arr.length; i++) {

    }
}

/* 递归遍历数组 */
void traverse(int[] arr, int i) {
    if (i == arr.length) {
        return;
    }
    // 前序位置
    traverse(arr, i + 1);
    // 后序位置
}

二叉树遍历方法

  • 先序遍历 (点击跳转原链接,讲的非常好) 根左右
    刷题笔记5——二叉树_第2张图片

  • 中序遍历 左根右
    刷题笔记5——二叉树_第3张图片

  • 后序遍历 左右根
    -就是围着树的外围绕一圈,如果发现一剪刀就能剪下的葡萄(必须是一颗葡萄)(也就是葡萄要一个一个掉下来,不能一口气掉超过1个这样),就把它剪下来,组成的就是后序遍历了。

你可能感兴趣的:(笔记,算法,数据结构,leetcode)