【算法 - 二叉树】“一套逻辑” 搞定所有二叉树性质题

101 阅读6分钟

二叉树 是由结点组成的层次结构,每个结点最多有两个子结点:左子结点和右子结点。结点之间的关系形成了树的层次结构,其中最顶层的结点称为根结点。

这种简单灵活的结构使得二叉树在存储和操作数据时非常 高效 ,在计算机科学中被广泛应用,为许多算法和数据操作提供了强大的基础。

了解二叉树的小伙伴都知道,二叉树可以根据形态或数据的不同产生很多分类,包括 满二叉树完全二叉树平衡二叉树二叉树搜索树 等等。

满二叉树(Full Binary Tree): 所有层都被完全填充的二叉树,没有缺失的结点。满二叉树的结点数量是一个等比数列,结点总数为 2h12^h-1 ,其中 hh 是树的高度。

004.FBT.jpg


完全二叉树(Complete Binary Tree): 完全二叉树是指除了最后一层外,所有层的结点都被完全填充,而且最后一层的结点都集中在左侧。不存在只含有右孩子而无左孩子的结点。

003.CBT.jpg


平衡二叉树(Balanced Binary Tree): 平衡二叉树是一种特殊的二叉树,其任意结点的左右子树高度差不超过1。这样的平衡性质确保在最坏情况下,树的高度不会太大,从而保持了检索和插入操作的高效性。

002.BBT.jpg


二叉搜索树(Binary Search Tree): 二叉搜索树是一种有序的二叉树。

1.结点 左子树 的值都 小于 该结点的值;

2.结点 右子树 的值都 大于 该结点的值;

3.任意结点的子树也都是二叉搜索树。

有序性质使得在 BST 中进行搜索、插入和删除等操作都具有高效的时间复杂度 O(logn)O(log n)

005.BST.jpg

那么给定一棵二叉树,如何判断 该树符合什么 类型 的二叉树呢?

下面进入本文的正题,用 一套递归逻辑 搞定二叉树的诸多题目!

// 二叉树的结构定义
public static class Node {
    public int value;
    public Node left;
    public Node right;

    public Node(int value) {
        this.value = value;
    }
}

递归逻辑

二叉树本身就很 “递归”,因此我们就可以利用好递归的特性,解决一系列二叉树有关的题目。

  1. 分析当前结点需要哪些二叉树的信息才能完成条件判断,整合成一个结构体;

  2. 分别递归调用左右子树寻找该信息;

  3. 得到左右子树的信息后,思考怎样对该信息加工判断。

下面我们运用该逻辑对不同二叉树形态进行判断。

满二叉树

判断一棵二叉树是否为 满二叉树。

public static class Info {
    public boolean isFull;
    public int height;

    public Info(boolean f, int h) {
        isFull = f;
        height = h;
    }
}

public static boolean isFull(Node head) {
    if (head == null) {
        return true;
    }
    return process(head).isFull;
}

public static Info process(Node h) {
    // base case
    if (h == null) {
        return new Info(true, 0);
    }
    Info leftInfo = process(h.left);
    Info rightInfo = process(h.right);
    boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
    int height = Math.max(leftInfo.height, rightInfo.height) + 1;
    return new Info(isFull, height);
}

思路

若一棵树为满二叉树,则 左右子树 也均为 满二叉树 且左右满二叉树的 高度相同。因此,需要的信息就包括两个:

1.是否是满二叉树

2.树高

代码解释

首先定义结构体,包含布尔类型的 isFull 和整形 height 两个信息。

如果输入的 h 为空,认为空树也是一颗满二叉树,返回 true

Info process(Node h) 函数进行主要判断:

  • base caseh 为空时,返回 (true,0) ,表示这是 满二叉树 且高度为 0

分别递归调用左右子树并记录信息。

  • 如果左右子树均为满二叉树且高度相同,则 isFull 设置为 true
  • height 高度信息设置为左右子树的 最大值 + 当前结点的 1 高度。

最终返回isFullheight两个信息,函数传入根结点,返回根结点的isFull值即可:process(head).isFull

平衡二叉树

判断一棵二叉树是否为 平衡二叉树。

public static class Info {
    public boolean isBalanced;
    public int height;

    public Info(boolean i, int h) {
        isBalanced = i;
        height = h;
    }
}

public static boolean isBalanced(Node head) {
    if (head == null) {
        return true;
    }
    return process(head).isBalanced;
}

public static Info process(Node h) {
    if (h == null) {
        return new Info(true, 0);
    }
    Info leftInfo = process(h.left);
    Info rightInfo = process(h.right);
    int height = Math.max(leftInfo.height, rightInfo.height) + 1;
    boolean isBalanced = true;
    if (!leftInfo.isBalanced || !rightInfo.isBalanced) {
        isBalanced = false;
    }
    if (Math.abs(leftInfo.height - rightInfo.height) > 1) {
        isBalanced = false;
    }
    return new Info(isBalanced, height);
}

思路

若一棵树为平衡二叉树,则 左右子树 也均为 平衡二叉树 且左右二叉子树的 高度之差不大于 1。因此,需要的信息就包括两个:

1.是否是平衡二叉树

2.树高

代码解释

首先定义结构体,包含布尔类型的 isBalanced 和整形 height 两个信息。

如果输入的 h 为空,认为空树也是一颗平衡二叉树,返回 true

Info process(Node h) 函数进行主要判断:

  • base caseh 为空时,返回 (true,0) ,表示这是 平衡二叉树 且高度为 0

分别递归调用左右子树并记录信息。

  • height 高度信息设置为左右子树的 最大值 + 当前结点的 1 高度。
  • 如果左右子树其中有一个 不是 平衡二叉树,整棵树不是平衡二叉树。
  • 如果左右子树的高度差 > 1,则也说明整棵树不是平衡二叉树。

最终返回isBalancedheight两个信息,函数传入根结点,返回根结点的isBalanced值即可:process(head).isBalanced

二叉搜索树

判断一棵二叉树是否为 二叉搜索树。

public static class Info {
    public boolean isBST;
    public int max;
    public int min;

    public Info(boolean i, int ma, int mi) {
        isBST = i;
        max = ma;
        min = mi;
    }
}

public static boolean isBST(Node head) {
    if (head == null) {
        return true;
    }
    return process(head).isBST;
}

public static Info process(Node h) {
    if (h == null) {
        return null;
    }
    Info leftInfo = process(h.left);
    Info rightInfo = process(h.right);
    int max = h.value;
    if (leftInfo != null) {
        max = Math.max(max, leftInfo.max);
    }
    if (rightInfo != null) {
        max = Math.max(max, rightInfo.max);
    }
    int min = h.value;
    if (leftInfo != null) {
        min = Math.min(min, leftInfo.min);
    }
    if (rightInfo != null) {
        min = Math.min(min, rightInfo.min);
    }
    boolean isBST = true;
    if (leftInfo != null && !leftInfo.isBST) {
        isBST = false;
    }
    if (rightInfo != null && !rightInfo.isBST) {
        isBST = false;
    }
    if (leftInfo != null && leftInfo.max >= h.value) {
        isBST = false;
    }
    if (rightInfo != null && rightInfo.min <= h.value) {
        isBST = false;
    }
    return new Info(isBST, max, min);
}

思路

若一棵树为二叉搜索树,则 左右子树 也均为 二叉搜索树 ,且满足:

  • 左子树的最大值 < 该结点的值
  • 右子树的最小值 > 该结点的值

即:左 < 中 < 右 。因此,需要的信息就包括三个:

1.是否是二叉搜索树

2.最大值

3.最小值

代码解释

首先定义结构体,包含布尔类型的 isBST 和整形 max、min 三个信息。

Info process(Node h) 函数进行主要判断:

  • base caseh 为空时,返回 null

分别递归调用左右子树并记录信息。

  • 最大最小值初始值设置为当前结点的值 h.value ;如果左右子树存在,则分别比较并更新 maxmin 值。
  • 如果左右子树中任意一个不为空且 不是 二叉搜索树,则整棵树 不是 二叉搜索树。
  • 如果左右子树的不满足“左 < 中 < 右”的要求,则也说明整棵树 不是 二叉搜索树。

最终返回isBSTmax、min三个信息,函数传入根结点,返回根结点的isBST值即可:process(head).isBST

总结

通过这三道题目的解答,相信小伙伴对二叉树的 递归套路 有了一定的认识。(套路太明显啦!)

下篇文章我们继续使用该 套路 解决二叉树的一些题目,并进行总结,帮助小伙伴直接拿下 二叉树!

~点赞 ~ 关注 ~ 不迷路 ~!!!

-------往期回顾-------

AC 此题,链表无敌!!!

归并排序,也有“套路”?

“二分”一定要有序么

你真的会找链表“中点”么?