前提:
二叉树的重要性:二叉树是一切复杂数据结构的基础,比如二叉堆,多叉树,字典树,线段树等等。就好像九九八十一难一样,你得先有悟空(掌握二叉树)之后的八十一难(基于二叉树的各种复杂的数据结构)才能渡过。
二叉树是一种递归的思维方式?
对的你没听错,它不仅仅是一种数据结构更代表着递归的思维方式,一切递归算法的本质就是把具体的问题抽象成树结构然后进行解决。大道至简,把复杂的抽象成简单的才是本质。
二叉树的介绍
1
/ \
2 3
/ / \
4 5 6
/ \
7 8
这就是一个二叉树我们来简单的介绍一下:
1子节点与父节点。
二叉树像不像高中那会的生物遗传图?(๑乛◡乛๑嘿嘿)
3的父节点是1 3的子节点是5和6不过在二叉树这里它们分为左子节点5与右子节点6
2以子节点为根的树称为子树。
比如节点3的左子树是节点5和7组成的树,同理节点3的右子树是节点6和8组成的树。
树=多个或者单个节点的组成(我的理解)--- 所以7节点组成的树是节点5的左子树。
3根节点与叶子节点。
与现实中实际的树不同,二叉树的根节点是1(没有父节点的节点),而没有子节点的节点称为叶子节点比如4,7,8
4二叉树最大深度或最大高度
看的是层数--所以最大深度是4
二叉树的分类
一 满二叉树
满二叉树就是每一层的节点都是满的,类似于遗传图中每个父母都有两个孩子
(此图来自于Github上labaladong大佬的图,接下来几张也是呀,如有侵权请告之,谢谢啦)
满二叉树的节点个数计算公式: 2^h - 1 其中h是满二叉树的最大深度
比如图中节点数: 2^4 - 1=15
二 完全二叉树
完全二叉树是指,二叉树的每一层的节点都紧凑靠左排列(因为除了最后一层其他层都是满的所以紧凑靠左的这个特征仅体现在最后一层),且除了最后一层,其他每层都必须是满的:
完全二叉树的特点:
1 完全二叉树的左右子树也是完全二叉树
2 完全二叉树一定有一个满二叉树
三 二叉搜索树
二叉搜索树(Binary(adj:二进制的) Search Tree,简称 BST)
关于二叉搜索树你记住两句话就欧克啦
1 先整体后细节 2左小右大
7
/ \
4 9
/ \ \
1 5 10
先解释左小右大,也就是节点x的左子树中的每个节点都小于x 节点x的右子树的每个节点都大于x,所以称为左小右大。
先整体后细节:先整体就是先把7当为x节点,看看符不符合,在依次检查4 9等。
举一个不是二叉搜索树的反例
7
/ \
4 9
/ \ \
1 8 10
先整体,显然7的左子树中8大于7不符合二叉搜索树所以其不是搜索树
BST数据结构的优点:
因为其左小右大的特性(最左边往左下移动一直呈现递减趋势,而最右边就是递增趋势),所以我们能够在BST中快速的找到我们想要的节点,跟它名字一样嘛,搜索二叉树所以其特点或者功能就是能够快速搜索我们想要的节点,哈哈哈。
ep(example):你要找一个x 节点,一看x比最上方的节点--根节点大,根节点的左子树你是看都不看的直接右边去了,直接减少了将近50%的节点数呢,减少了50%的时间。๑乛◡乛๑嘿嘿
四 高度平衡二叉树
平衡二叉树的特点或者说是辨别方法:它的每一个节点,对的你没有听错它的每一个是每一个节点的左右子树的高度差不超过1。
ep:
1
/ \
2 3
/ / \
4 5 6
\
7
1的左子树高度是2,右子树高度是3
2的左子树高度是1,右子树高度是0!!!也符合
4的左子树高度是0,右子树高度是0。哈哈哈相差不超过1所以也符合。
错误示范:
1
/ \
2 3
/ / \
4 5 6
\ \
8 7
2的左子树高度是2,右子树是0.相差为2超过了1所以不符合。
平衡二叉树有一个重要的性质:
加入平衡二叉树有N个节点,那么平衡二叉树的高度就是O(logN)
那么为什么叫平衡呢,我的理解是如果能保证树的高度是O(logN)那么其数据结构的增删查改的效率就会很高很高。
万物平衡的话那不就兴兴向荣蓬勃发展了嘛 ,效率也就高了๑乛◡乛๑嘿嘿
当然有极端情况(完全不平衡~)
1
\
2
\
3
\
4
\
5
1的左子树节点0右子树节点4.其就等同于单链表了,在树中进行的增删查改效率会大幅度降低,因为其链表设计到指针的移动。
五 自平衡二叉树
之前提到的基于二叉树的高级数据结构红黑树就是自平衡二叉树。
自二叉树的核心目的:
通过自动调整树的结构确保树的高度保持在对数级别(O(logN))从而到达一种平衡状态让增删查改的效率大幅度提高。
普通二叉树在最坏的情况下会退化成链表(高度O(N))从而让增删查改等操作效率大幅度下降。而平衡二叉树于普通二叉树不同之处在于其引入了旋转操作以及平衡条件来维持平衡,从而维持高效率的工作。
注:自平衡二叉树又包括了很多二叉树
1平衡条件:
- AVL 树:任意节点的左右子树高度差不超过 1(严格平衡)。
- 红黑树:通过颜色标记和规则间接控制树的平衡(非严格平衡,但能保证最长路径(包含红节点的)不超过最短路径(全部是黑节点的)的 2 倍)。
2 旋转操作:
当插入或删除节点导致树失衡(不符合平衡条件时,比如高度差大于1或者最长路径超过了最长路径的两倍)时,通过左旋或右旋调整子树结构,恢复平衡。旋转操作是自平衡的核心手段,能在 \(O(1)\) 时间内完成局部结构调整。
红黑树节点的五条核心规则(不要死记了解便可):
1 节点只有红色或者黑色
2 根节点必须是黑色
3 叶子节点(最底下那几个节点)都是黑色
4 红色节点的两个子节点必须是黑色
5 从任一节点到叶子节点的所有路径上的黑色节点的数量相同。
注:之前提到平衡条件中红黑树的最长路径不能超过最短路径的两倍。这里详细的说一下
- 最短路径:全黑节点,长度为 h(黑色高度)。
- 最长路径:红黑交替,长度为 2h(红色节点不影响黑色高度)。 因此,树的高度最多为 \(2\log(N+1)\),保证操作复杂度为 \(O(\log N)\)
关于红黑树的可视化操作有兴趣的话大家可以参考一下这个大佬的视频呀!
二叉树的实现方式(人话就是创建一个二叉树)
最常见的二叉树就是类似于链表那样的链式存储结构,每个二叉树有指向左右节点的指针。像八叉一样。
1方法一 运用TreeNode类创建二叉树
class TreeNode: 定义一个模板--像流水线的操作模板那样咱们也定义一个 class
def __init__(self, x: int): 定义一个初始化的函数 指定x为整数型 其中self是一个对象相当于流水线上的一个物件
self.val = x 让物件的值等于x
self.left = None 物件的左指针为空值
self.right = None 物件的右指针为空值
# 你可以这样构建一棵二叉树:
root = TreeNode(1) 根节点为1
root.left = TreeNode(2) 1的左子节点为2
root.right = TreeNode(3) 1的右子节点为3
root.left.left = TreeNode(4) 聪明的你后面肯定会啦!
root.right.left = TreeNode(5)
root.right.right = TreeNode(6)
# 构建出来的二叉树是这样的:
# 1
# / \
# 2 3
# / / \
# 4 5 6
方法二 运用哈希表(类似于字典的结构也有键和值)创建二叉树
# 1 -> [2, 3]
# 2 -> [4]
# 3 -> [5, 6]
tree = {
1: [2, 3], #1的子节点为2 3
2: [4], #2的节点为4
3: [5, 6] #聪明的你应该会啦哈哈哈
}
结果
1
/ \
2 3
/ / \
4 5 6
简洁版:
二叉树的重要性与基本概念
二叉树是复杂数据结构的基础,如二叉堆、多叉树、字典树、线段树等均由其衍生。掌握二叉树如同掌握“悟空”的能力,是应对后续“八十一难”(高级数据结构)的前提。它不仅是一种数据结构,更体现了递归的思维方式——将问题抽象为树结构并通过递归解决,化繁为简。
示例二叉树结构
1
/ \
2 3
/ / \
4 5 6
/ \
7 8
核心术语解析
- 父节点与子节点:如节点1是节点2和3的父节点,节点5和6是节点3的左右子节点。
- 子树:以某节点为根的树称为子树。例如,节点3的左子树为节点5和7构成的树。
- 根节点与叶节点:无父节点的节点为根节点(如节点1),无子节点的节点为叶节点(如节点4、7、8)。
- 深度/高度:从根到最远叶节点的层数。图中最大深度为4。
二叉树的分类
满二叉树
每一层节点均满,形如遗传图中“每对父母有两个孩子”。节点数公式为 (2^h - 1)((h)为深度)。
完全二叉树
除最后一层外均为满层,且最后一层节点紧凑靠左排列。其特点包括:
- 左右子树均为完全二叉树;
- 必包含一个满二叉树。
二叉搜索树(BST)
核心特性为“左小右大”:
- 任意节点左子树的值均小于该节点,右子树反之。
- 搜索效率高,通过比较可快速排除半数节点。
反例:若左子树存在大于父节点的值(如节点8 > 7),则非BST。
平衡二叉树
每个节点的左右子树高度差不超过1。平衡性保证树高为 (O(\log N)),操作效率显著优于退化链表((O(N)))。
自平衡二叉树
通过旋转操作维持平衡,如AVL树(严格平衡)和红黑树(非严格平衡)。红黑树规则包括:
- 节点为红或黑;
- 根与叶节点为黑;
- 红节点的子节点必为黑;
- 从任意节点到叶的路径黑节点数相同。
二叉树的实现
链式存储(类实现)
class TreeNode:
def __init__(self, val: int):
self.val = val
self.left = None
self.right = None
# 构建示例
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.right.left = TreeNode(5)
root.right.right = TreeNode(6)
哈希表存储
tree = {
1: [2, 3],
2: [4],
3: [5, 6]
}
通过以上方法,可直观理解二叉树的逻辑结构与实现方式,为后续高级数据结构的学习奠定基础。
我从未遇见过不曾打丢一球的高尔夫球选手,也从未见过不曾伤心过的恋人,更未见过从不亏钱的富人。失败并不可怕,可怕的是放弃。 ———《富爸爸,穷爸爸》