跳转到内容

二叉树:修订间差异

来自代码酷
Admin留言 | 贡献
Page creation by admin bot
 
Admin留言 | 贡献
Page update by admin bot
 
第1行: 第1行:
= 二叉树 =
{{DISPLAYTITLE:二叉树}}


'''二叉树'''(Binary Tree)是计算机科学中最基础且重要的非线性数据结构之一,由节点(Node)组成,每个节点最多有两个子节点,分别称为'''左子节点'''和'''右子节点'''。二叉树广泛应用于搜索、排序、数据库索引和编译器设计等领域。
'''二叉树'''(Binary Tree)是计算机科学中最基础且重要的[[数据结构]]之一,广泛应用于算法设计、数据库索引、文件系统等领域。它是一种每个节点最多有两个子节点的树形结构,这两个子节点通常被称为'''左子节点'''和'''右子节点'''


== 基本概念 ==
== 基本概念 ==


=== 定义 ===
=== 定义 ===
二叉树是满足以下条件的树形结构:
二叉树是满足以下条件的[[树 (数据结构)|树]]:
* 每个节点最多有两个子节点。
* 每个节点最多有两个子节点(左子节点和右子节点)。
* 子节点有明确的左右之分(即使只有一个子节点,也必须区分左或右)。
* 子节点有明确的左右顺序之分(即使只有一个子节点,也必须指明是左还是右)。


数学上,二叉树可以递归定义:
数学上可以递归定义为:
<math>T = \begin{cases}
<math>T = \begin{cases}
\emptyset & \text{空树} \\
\emptyset & \text{空树} \\
(r, L, R) & \text{根节点为 } r \text{,左子树为 } L \text{,右子树为 } R
(r, T_L, T_R) & \text{根节点为 } r \text{,左子树为 } T_L \text{,右子树为 } T_R
\end{cases}</math>
\end{cases}</math>


=== 术语 ===
=== 术语 ===
* '''根节点'''(Root):没有父节点的顶层节点。
* '''根节点'''(Root):没有父节点的顶层节点
* '''叶子节点'''(Leaf):没有子节点的节点。
* '''叶节点'''(Leaf):没有子节点的节点
* '''内部节点''':至少有一个子节点的节点。
* '''内部节点''':至少有一个子节点的非根节点
* '''深度'''(Depth):从根节点到该节点的路径长度(根节点深度为0)。
* '''深度''':从根到该节点的唯一路径的边数
* '''高度'''(Height):从该节点到最远叶子节点的路径长度(叶子节点高度为0)。
* '''高度''':从该节点到最深叶节点的最长路径的边数


<mermaid>
<mermaid>
第27行: 第27行:
     A((根节点)) --> B((左子节点))
     A((根节点)) --> B((左子节点))
     A --> C((右子节点))
     A --> C((右子节点))
     B --> D((叶子节点))
     B --> D((叶节点))
     B --> E((叶子节点))
     B --> E((叶节点))
     C --> F((叶子节点))
     C --> F((叶节点))
</mermaid>
</mermaid>


== 二叉树类型 ==
== 二叉树类型 ==


=== 满二叉树(Full Binary Tree) ===
=== 满二叉树 ===
每个节点都有0个或2个子节点。
每一层的节点都达到最大数量,即第<math>i</math>层有<math>2^{i-1}</math>个节点。


=== 完全二叉树(Complete Binary Tree) ===
=== 完全二叉树 ===
除最后一层外,其他层节点数达到最大值,且最后一层节点靠左排列。
除最后一层外,其他层节点都满,且最后一层节点从左向右连续排列。
 
=== 完美二叉树(Perfect Binary Tree) ===
所有叶子节点在同一层,且每个非叶子节点都有两个子节点。


=== 二叉搜索树(BST) ===
=== 二叉搜索树(BST) ===
左子树所有节点值小于根节点,右子树所有节点值大于根节点。
对于任意节点:
* 左子树所有节点的值 < 当前节点的值
* 右子树所有节点的值 > 当前节点的值


== 存储方式 ==
== 基本操作 ==


=== 链式存储 ===
=== 遍历方式 ===
通过节点对象和指针实现(或引用):
二叉树有四种基本遍历方式(以下示例代码使用Python实现):


<syntaxhighlight lang="python">
==== 前序遍历 ====
class TreeNode:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None
 
# 示例构建
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
</syntaxhighlight>
 
=== 顺序存储(数组表示) ===
适用于完全二叉树,索引规则:
* 父节点索引:<math>i</math>
* 左子节点索引:<math>2i + 1</math>
* 右子节点索引:<math>2i + 2</math>
 
== 遍历算法 ==
 
=== 深度优先遍历(DFS) ===
{| class="wikitable"
|+ 遍历方式对比
! 遍历方式 !! 顺序 !! 递归实现示例(Python)
|-
| 前序遍历 || 根 → 左 → 右 ||
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
def preorder(root):
def preorder(root):
     if root:
     if root:
         print(root.value)
         print(root.val)     # 访问根节点
         preorder(root.left)
         preorder(root.left)   # 遍历左子树
         preorder(root.right)
         preorder(root.right) # 遍历右子树
</syntaxhighlight>
</syntaxhighlight>
|-
 
| 中序遍历 || 左 → 根 → 右 ||
==== 中序遍历 ====
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
def inorder(root):
def inorder(root):
     if root:
     if root:
         inorder(root.left)
         inorder(root.left)   # 遍历左子树
         print(root.value)
         print(root.val)     # 访问根节点
         inorder(root.right)
         inorder(root.right)   # 遍历右子树
</syntaxhighlight>
</syntaxhighlight>
|-
 
| 后序遍历 || 左 → 右 → 根 ||
==== 后序遍历 ====
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
def postorder(root):
def postorder(root):
     if root:
     if root:
         postorder(root.left)
         postorder(root.left) # 遍历左子树
         postorder(root.right)
         postorder(root.right) # 遍历右子树
         print(root.value)
         print(root.val)     # 访问根节点
</syntaxhighlight>
</syntaxhighlight>
|}


=== 广度优先遍历(BFS/层序遍历) ===
==== 层序遍历 ====
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
from collections import deque
from collections import deque


def level_order(root):
def level_order(root):
     queue = deque([root]) if root else deque()
    if not root:
        return
     queue = deque([root])
     while queue:
     while queue:
         node = queue.popleft()
         node = queue.popleft()
         print(node.value)
         print(node.val)
         if node.left: queue.append(node.left)
         if node.left:
         if node.right: queue.append(node.right)
            queue.append(node.left)
         if node.right:
            queue.append(node.right)
</syntaxhighlight>
</syntaxhighlight>


== 实际应用案例 ==
=== 插入与删除 ===
以二叉搜索树为例:


=== 案例1:表达式树 ===
<syntaxhighlight lang="python">
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
 
def insert(root, val):
    if not root:
        return TreeNode(val)
    if val < root.val:
        root.left = insert(root.left, val)
    else:
        root.right = insert(root.right, val)
    return root
 
def delete(root, val):
    if not root:
        return None
    if val < root.val:
        root.left = delete(root.left, val)
    elif val > root.val:
        root.right = delete(root.right, val)
    else:
        if not root.left:
            return root.right
        if not root.right:
            return root.left
        # 找到右子树的最小节点
        temp = root.right
        while temp.left:
            temp = temp.left
        root.val = temp.val
        root.right = delete(root.right, temp.val)
    return root
</syntaxhighlight>
 
== 实际应用 ==
 
=== 表达式树 ===
用于表示数学表达式,其中:
用于表示数学表达式,其中:
* 内部节点是运算符
* 内部节点是运算符
* 叶子节点是操作数
* 叶节点是操作数


<mermaid>
<mermaid>
第132行: 第148行:
     + --> 5((5))
     + --> 5((5))
</mermaid>
</mermaid>
表示表达式:<math>(2 + 5) * 3</math>
表示表达式:<code>(2 + 5) * 3</code>
 
=== 哈夫曼编码 ===
用于数据压缩,通过构建最优二叉树实现高效编码。


=== 案例2:哈夫曼编码树 ===
=== 数据库索引 ===
用于数据压缩,频率高的字符使用短编码,频率低的字符使用长编码。
许多数据库系统使用B树、B+树(二叉树的扩展)来加速数据检索。


== 复杂度分析 ==
== 复杂度分析 ==
{| class="wikitable"
{| class="wikitable"
|+ 操作时间复杂度(n为节点数)
|+ 二叉树操作时间复杂度
! 操作 !! 平均情况 !! 最坏情况
! 操作 !! 平均情况 !! 最坏情况
|-
|-
| 查找 || <math>O(\log n)</math>(BST) || <math>O(n)</math>(退化为链表)
| 查找 || <math>O(\log n)</math> || <math>O(n)</math>
|-
|-
| 插入/删除 || <math>O(\log n)</math> || <math>O(n)</math>
| 插入 || <math>O(\log n)</math> || <math>O(n)</math>
|-
| 删除 || <math>O(\log n)</math> || <math>O(n)</math>
|-
|-
| 遍历 || <math>O(n)</math> || <math>O(n)</math>
| 遍历 || <math>O(n)</math> || <math>O(n)</math>
第150行: 第172行:


== 进阶话题 ==
== 进阶话题 ==
* '''平衡二叉树'''(AVL树/红黑树):通过旋转保持平衡,确保操作效率。
* '''线索二叉树''':利用空指针存储遍历信息。
* '''B树/B+树''':数据库索引使用的多路平衡树。


== 练习问题 ==
* '''平衡二叉树''':AVL树、红黑树等,通过旋转操作保持平衡
1. 实现二叉树的反转(镜像)
* '''线索二叉树''':利用空指针存储遍历信息
* '''二叉堆''':用于实现优先队列
 
== 练习题 ==
 
1. 实现一个函数判断两棵二叉树是否相同
2. 计算二叉树的最大深度
2. 计算二叉树的最大深度
3. 验证二叉搜索树的有效性
3. 将有序数组转换为平衡二叉搜索树
4. 实现二叉树的序列化与反序列化


<syntaxhighlight lang="python">
{{数据结构导航}}
# 问题1解答示例
def invert_tree(root):
    if root:
        root.left, root.right = invert_tree(root.right), invert_tree(root.left)
    return root
</syntaxhighlight>


{{数据结构与算法}}
[[Category:数据结构]]
[[Category:树结构]]


[[Category:计算机科学]]
[[Category:计算机科学]]
[[Category:数据结构与算法]]
[[Category:面试技巧]]
[[Category:非线性数据结构]]
[[Category:数据结构基础]]

2025年5月12日 (一) 00:29的最新版本


二叉树(Binary Tree)是计算机科学中最基础且重要的数据结构之一,广泛应用于算法设计、数据库索引、文件系统等领域。它是一种每个节点最多有两个子节点的树形结构,这两个子节点通常被称为左子节点右子节点

基本概念[编辑 | 编辑源代码]

定义[编辑 | 编辑源代码]

二叉树是满足以下条件的

  • 每个节点最多有两个子节点(左子节点和右子节点)。
  • 子节点有明确的左右顺序之分(即使只有一个子节点,也必须指明是左还是右)。

数学上可以递归定义为: T={空树(r,TL,TR)根节点为 r,左子树为 TL,右子树为 TR

术语[编辑 | 编辑源代码]

  • 根节点(Root):没有父节点的顶层节点
  • 叶节点(Leaf):没有子节点的节点
  • 内部节点:至少有一个子节点的非根节点
  • 深度:从根到该节点的唯一路径的边数
  • 高度:从该节点到最深叶节点的最长路径的边数

graph TD A((根节点)) --> B((左子节点)) A --> C((右子节点)) B --> D((叶节点)) B --> E((叶节点)) C --> F((叶节点))

二叉树类型[编辑 | 编辑源代码]

满二叉树[编辑 | 编辑源代码]

每一层的节点都达到最大数量,即第i层有2i1个节点。

完全二叉树[编辑 | 编辑源代码]

除最后一层外,其他层节点都满,且最后一层节点从左向右连续排列。

二叉搜索树(BST)[编辑 | 编辑源代码]

对于任意节点:

  • 左子树所有节点的值 < 当前节点的值
  • 右子树所有节点的值 > 当前节点的值

基本操作[编辑 | 编辑源代码]

遍历方式[编辑 | 编辑源代码]

二叉树有四种基本遍历方式(以下示例代码使用Python实现):

前序遍历[编辑 | 编辑源代码]

def preorder(root):
    if root:
        print(root.val)      # 访问根节点
        preorder(root.left)   # 遍历左子树
        preorder(root.right)  # 遍历右子树

中序遍历[编辑 | 编辑源代码]

def inorder(root):
    if root:
        inorder(root.left)    # 遍历左子树
        print(root.val)      # 访问根节点
        inorder(root.right)   # 遍历右子树

后序遍历[编辑 | 编辑源代码]

def postorder(root):
    if root:
        postorder(root.left)  # 遍历左子树
        postorder(root.right) # 遍历右子树
        print(root.val)      # 访问根节点

层序遍历[编辑 | 编辑源代码]

from collections import deque

def level_order(root):
    if not root:
        return
    queue = deque([root])
    while queue:
        node = queue.popleft()
        print(node.val)
        if node.left:
            queue.append(node.left)
        if node.right:
            queue.append(node.right)

插入与删除[编辑 | 编辑源代码]

以二叉搜索树为例:

class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def insert(root, val):
    if not root:
        return TreeNode(val)
    if val < root.val:
        root.left = insert(root.left, val)
    else:
        root.right = insert(root.right, val)
    return root

def delete(root, val):
    if not root:
        return None
    if val < root.val:
        root.left = delete(root.left, val)
    elif val > root.val:
        root.right = delete(root.right, val)
    else:
        if not root.left:
            return root.right
        if not root.right:
            return root.left
        # 找到右子树的最小节点
        temp = root.right
        while temp.left:
            temp = temp.left
        root.val = temp.val
        root.right = delete(root.right, temp.val)
    return root

实际应用[编辑 | 编辑源代码]

表达式树[编辑 | 编辑源代码]

用于表示数学表达式,其中:

  • 内部节点是运算符
  • 叶节点是操作数

graph TD *((*)) --> +((+)) * --> 3((3)) + --> 2((2)) + --> 5((5))

表示表达式:(2 + 5) * 3

哈夫曼编码[编辑 | 编辑源代码]

用于数据压缩,通过构建最优二叉树实现高效编码。

数据库索引[编辑 | 编辑源代码]

许多数据库系统使用B树、B+树(二叉树的扩展)来加速数据检索。

复杂度分析[编辑 | 编辑源代码]

二叉树操作时间复杂度
操作 平均情况 最坏情况
查找 O(logn) O(n)
插入 O(logn) O(n)
删除 O(logn) O(n)
遍历 O(n) O(n)

进阶话题[编辑 | 编辑源代码]

  • 平衡二叉树:AVL树、红黑树等,通过旋转操作保持平衡
  • 线索二叉树:利用空指针存储遍历信息
  • 二叉堆:用于实现优先队列

练习题[编辑 | 编辑源代码]

1. 实现一个函数判断两棵二叉树是否相同 2. 计算二叉树的最大深度 3. 将有序数组转换为平衡二叉搜索树 4. 实现二叉树的序列化与反序列化

模板:数据结构导航