数据结构基础:树

树数据结构介绍

目录

  1. 什么是树?
  2. 树的基本术语
  3. 树的特点
  4. 二叉树
  5. 树的遍历
  6. 常见的树类型
  7. 树的应用场景
  8. Python实现示例

什么是树?

树(Tree) 是一种非线性的数据结构,由节点(Node)和连接节点的边(Edge)组成。它模拟了自然界中树的结构,由根向下延伸。

树的图示

        A           <- 根节点
       /|\
      B C D         <- A的子节点
     /|   |\
    E F   G H       <- B和D的子节点

树的基本术语

1. 节点(Node)

  • 树中的每个元素称为节点
  • 节点包含数据和指向其他节点的引用

2. 根节点(Root)

  • 树的最顶端节点,没有父节点
  • 每棵树只有一个根节点

3. 父节点(Parent)

  • 如果节点A连接到节点B,且A在B的上方,则A是B的父节点

4. 子节点(Child)

  • 与父节点相对应,B是A的子节点

5. 叶子节点(Leaf)

  • 没有子节点的节点
  • 也称为终端节点

6. 内部节点(Internal Node)

  • 至少有一个子节点的节点

7. 兄弟节点(Siblings)

  • 拥有相同父节点的节点

8. 边(Edge)

  • 连接两个节点的链接

9. 路径(Path)

  • 从一个节点到另一个节点的节点序列

10. 深度(Depth)

  • 从根节点到某个节点的边数
  • 根节点的深度为0

11. 高度(Height)

  • 从某个节点到叶子节点的最长路径的边数
  • 树的高度是根节点的高度

12. 层级(Level)

  • 节点的深度 + 1
  • 根节点在第1层

13. 子树(Subtree)

  • 树中的任意节点及其所有后代节点构成的树

树的特点

  1. 层次结构:树具有明确的层次关系
  2. 唯一路径:从根节点到任意节点只有一条路径
  3. 无环:树是无环的连通图
  4. 节点数 = 边数 + 1:有n个节点的树有n-1条边

二叉树

二叉树(Binary Tree) 是最常用的树结构,每个节点最多有两个子节点。

二叉树的类型

1. 完全二叉树(Complete Binary Tree)
  • 除了最后一层,其他层都是满的
  • 最后一层的节点从左到右连续排列
        1
       / \
      2   3
     / \  /
    4  5 6
2. 满二叉树(Full Binary Tree)
  • 每个节点要么有0个子节点,要么有2个子节点
        1
       / \
      2   3
         / \
        4   5
3. 完美二叉树(Perfect Binary Tree)
  • 所有内部节点都有两个子节点
  • 所有叶子节点在同一层
        1
       / \
      2   3
     / \ / \
    4  5 6  7
4. 平衡二叉树(Balanced Binary Tree)
  • 任何节点的左右子树高度差不超过1
  • 例如:AVL树、红黑树
5. 二叉搜索树(Binary Search Tree, BST)
  • 左子树的所有节点值 < 根节点值
  • 右子树的所有节点值 > 根节点值
  • 左右子树也是二叉搜索树
        50
       /  \
      30   70
     / \   / \
   20  40 60  80

树的遍历

遍历是访问树中所有节点的过程。主要有以下几种方式:

1. 深度优先遍历(DFS - Depth First Search)

前序遍历(Pre-order)

顺序:根 → 左 → 右

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

示例:A → B → E → F → C → D → G → H

中序遍历(In-order)

顺序:左 → 根 → 右

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

示例:E → B → F → A → C → G → D → H

注意:对于二叉搜索树,中序遍历得到有序序列!

后序遍历(Post-order)

顺序:左 → 右 → 根

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

示例:E → F → B → C → G → H → D → A

2. 广度优先遍历(BFS - Breadth First Search)

层序遍历(Level-order)

逐层从左到右访问

from collections import deque

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

示例:A → B → C → D → E → F → G → H


常见的树类型

1. 二叉搜索树(BST)

  • 用于快速查找、插入和删除
  • 平均时间复杂度:O(log n)

2. AVL树

  • 自平衡的二叉搜索树
  • 保证任何节点的左右子树高度差不超过1

3. 红黑树

  • 另一种自平衡二叉搜索树
  • Java的TreeMap、C++的map底层实现

4. B树和B+树

  • 多路搜索树
  • 用于数据库和文件系统

5. 堆(Heap)

  • 完全二叉树
  • 最大堆:父节点 ≥ 子节点
  • 最小堆:父节点 ≤ 子节点
  • 用于优先队列和堆排序

6. 字典树(Trie)

  • 用于字符串检索
  • 自动补全、拼写检查

7. 线段树(Segment Tree)

  • 用于区间查询和更新

8. 哈夫曼树

  • 用于数据压缩
  • 构造最优前缀编码

树的应用场景

  1. 文件系统:文件夹和文件的层次结构
  2. 数据库索引:B树、B+树用于高效查询
  3. HTML/XML解析:DOM树
  4. 编译器:抽象语法树(AST)
  5. 人工智能:决策树、游戏树(如国际象棋)
  6. 网络路由:路由表的组织
  7. 组织结构:公司的层级结构
  8. 优先级管理:堆实现优先队列
  9. 自动补全:字典树
  10. 图形界面:GUI组件树

Python实现示例

二叉树节点定义

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

完整的二叉搜索树实现

class BinarySearchTree:
    def __init__(self):
        self.root = None
    
    # 插入节点
    def insert(self, data):
        if self.root is None:
            self.root = TreeNode(data)
        else:
            self._insert_recursive(self.root, data)
    
    def _insert_recursive(self, node, data):
        if data < node.data:
            if node.left is None:
                node.left = TreeNode(data)
            else:
                self._insert_recursive(node.left, data)
        else:
            if node.right is None:
                node.right = TreeNode(data)
            else:
                self._insert_recursive(node.right, data)
    
    # 查找节点
    def search(self, data):
        return self._search_recursive(self.root, data)
    
    def _search_recursive(self, node, data):
        if node is None:
            return False
        if node.data == data:
            return True
        elif data < node.data:
            return self._search_recursive(node.left, data)
        else:
            return self._search_recursive(node.right, data)
    
    # 前序遍历
    def preorder_traversal(self):
        result = []
        self._preorder_helper(self.root, result)
        return result
    
    def _preorder_helper(self, node, result):
        if node:
            result.append(node.data)
            self._preorder_helper(node.left, result)
            self._preorder_helper(node.right, result)
    
    # 中序遍历
    def inorder_traversal(self):
        result = []
        self._inorder_helper(self.root, result)
        return result
    
    def _inorder_helper(self, node, result):
        if node:
            self._inorder_helper(node.left, result)
            result.append(node.data)
            self._inorder_helper(node.right, result)
    
    # 后序遍历
    def postorder_traversal(self):
        result = []
        self._postorder_helper(self.root, result)
        return result
    
    def _postorder_helper(self, node, result):
        if node:
            self._postorder_helper(node.left, result)
            self._postorder_helper(node.right, result)
            result.append(node.data)
    
    # 层序遍历
    def levelorder_traversal(self):
        if not self.root:
            return []
        
        from collections import deque
        result = []
        queue = deque([self.root])
        
        while queue:
            node = queue.popleft()
            result.append(node.data)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        
        return result
    
    # 获取树的高度
    def height(self):
        return self._height_recursive(self.root)
    
    def _height_recursive(self, node):
        if node is None:
            return -1  # 空树高度为-1,单节点高度为0
        return 1 + max(self._height_recursive(node.left), 
                       self._height_recursive(node.right))

使用示例

# 创建二叉搜索树
bst = BinarySearchTree()

# 插入节点
nodes = [50, 30, 70, 20, 40, 60, 80]
for node in nodes:
    bst.insert(node)

# 查找节点
print(bst.search(40))  # True
print(bst.search(25))  # False

# 各种遍历
print("前序遍历:", bst.preorder_traversal())   # [50, 30, 20, 40, 70, 60, 80]
print("中序遍历:", bst.inorder_traversal())    # [20, 30, 40, 50, 60, 70, 80]
print("后序遍历:", bst.postorder_traversal())  # [20, 40, 30, 60, 80, 70, 50]
print("层序遍历:", bst.levelorder_traversal()) # [50, 30, 70, 20, 40, 60, 80]

# 获取树的高度
print("树的高度:", bst.height())  # 2

学习建议

初学者路径

  1. 理解概念:先掌握树的基本术语和概念
  2. 手动画图:用笔画出树的结构,理解各种遍历方式
  3. 实现简单树:从二叉树开始,实现基本的插入和遍历
  4. 练习遍历:重点理解递归遍历和层序遍历
  5. 学习BST:理解二叉搜索树的特性
  6. 进阶学习:AVL树、红黑树、堆等高级树结构

练习题推荐

  • LeetCode 104: 二叉树的最大深度
  • LeetCode 94: 二叉树的中序遍历
  • LeetCode 102: 二叉树的层序遍历
  • LeetCode 98: 验证二叉搜索树
  • LeetCode 226: 翻转二叉树

时间复杂度总结

操作二叉搜索树(平均)二叉搜索树(最坏)平衡树
搜索O(log n)O(n)O(log n)
插入O(log n)O(n)O(log n)
删除O(log n)O(n)O(log n)
遍历O(n)O(n)O(n)

总结

树是一种强大的数据结构,它:

  • 提供了层次化的数据组织方式
  • 支持高效的搜索、插入和删除操作
  • 广泛应用于各种实际场景
  • 是学习算法和数据结构的重要基础
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiamsWu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值