【数据结构】二叉树

二叉树的基本概念

二叉树是每个节点最多有两个子节点的树结构,这两个子节点分别称为左子节点右子节点。与普通树相比,二叉树具有更严格的结构限制:

  • 根节点:最顶层的节点,没有父节点

  • 叶子节点:没有子节点的末端节点

  • 子树:某个节点及其所有后代组成的树

  • 深度:从根节点到该节点的路径长度(根节点深度为0)

  • 高度:从节点到最深叶子节点的路径长度(叶子节点高度为0)

与普通树的区别

  1. 普通树节点可以有任意数量的子节点

  2. 二叉树严格区分左右子节点顺序

  3. 空树也是有效的二叉树

二叉树的常见类型

1. 满二叉树

  • 定义:每个节点都有0或2个子节点

  • 性质:叶子节点数 = 内部节点数 + 1

  • 示例

        A
       / \
      B   C
     / \ 
    D   E

2. 完全二叉树

  • 定义:除最后一层外完全填充,且最后一层节点靠左排列

  • 特点:适合数组存储,堆结构的基础

  • 示例

        A
       / \
      B   C
     / \ /
    D  E F

3. 二叉搜索树(BST)

  • 关键性质:左子树所有节点值 < 根节点值 < 右子树所有节点值

  • 操作效率:查找/插入/删除平均O(log n)

  • 退化风险:可能退化为链表(最坏O(n))

4. 平衡二叉树(AVL)

  • 平衡条件:任意节点左右子树高度差≤1

  • 维护操作:通过旋转保持平衡

  • 优势:保证O(log n)操作复杂度

二叉树的存储实现

链式存储(最常用)

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

优点

  • 直观反映树结构

  • 动态扩展方便

  • 支持任意形状的树

缺点

  • 指针占用额外空间

  • 内存非连续访问

顺序存储(数组表示)

对于完全二叉树,父子节点索引关系:

  • 父节点i的左子节点:2i+1

  • 父节点i的右子节点:2i+2

  • 子节点i的父节点:(i-1)/2

适用场景

  • 堆结构实现

  • 需要快速随机访问节点

  • 内存受限环境

二叉树的遍历方法

深度优先遍历(DFS)

递归实现
// 前序遍历:根→左→右
void preorder(TreeNode* root) {
    if (!root) return;
    printf("%d ", root->val);
    preorder(root->left);
    preorder(root->right);
}

// 中序遍历:左→根→右(BST得到有序序列)
void inorder(TreeNode* root) {
    if (!root) return;
    inorder(root->left);
    printf("%d ", root->val);
    inorder(root->right);
}
非递归实现(使用栈)
void preorderIterative(TreeNode* root) {
    stack s;
    if (root) s.push(root);
    while (!s.empty()) {
        TreeNode* node = s.top(); s.pop();
        printf("%d ", node->val);
        if (node->right) s.push(node->right);
        if (node->left) s.push(node->left);
    }
}

广度优先遍历(BFS)

void levelOrder(TreeNode* root) {
    queue q;
    if (root) q.push(root);
    while (!q.empty()) {
        int size = q.size();
        for (int i = 0; i < size; i++) {
            TreeNode* node = q.front(); q.pop();
            printf("%d ", node->val);
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
    }
}

二叉树的核心操作

二叉搜索树操作

// 插入节点
TreeNode* insert(TreeNode* root, int val) {
    if (!root) return new TreeNode(val);
    if (val < root->val) 
        root->left = insert(root->left, val);
    else 
        root->right = insert(root->right, val);
    return root;
}

// 删除节点
TreeNode* deleteNode(TreeNode* root, int key) {
    if (!root) return nullptr;
    if (key < root->val) {
        root->left = deleteNode(root->left, key);
    } else if (key > root->val) {
        root->right = deleteNode(root->right, key);
    } else {
        if (!root->left) return root->right;
        if (!root->right) return root->left;
        TreeNode* minNode = findMin(root->right);
        root->val = minNode->val;
        root->right = deleteNode(root->right, root->val);
    }
    return root;
}

AVL树平衡调整

// 右旋操作
TreeNode* rightRotate(TreeNode* y) {
    TreeNode* x = y->left;
    y->left = x->right;
    x->right = y;
    // 更新高度...
    return x;
}

// 平衡因子检查
int getBalance(TreeNode* node) {
    return getHeight(node->left) - getHeight(node->right);
}

二叉树的高级应用

1. 数据库索引

  • B树/B+树:多路平衡搜索树,减少磁盘I/O

  • 特点:节点包含多个键,保持平衡

2. 哈夫曼编码

struct HuffmanNode {
    char data;
    unsigned freq;
    HuffmanNode *left, *right;
};
// 构建过程:优先队列合并最小频率节点

3. 表达式树

     +
    / \
   *   5
  / \
 2   3

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

4. 决策树算法

  • 每个内部节点表示特征测试

  • 分支代表测试结果

  • 叶节点存储类别标签

性能分析与优化

时间复杂度比较

操作 普通二叉树 平衡二叉树 哈希表
查找 O(n) O(log n) O(1)
插入 O(n) O(log n) O(1)
删除 O(n) O(log n) O(1)
范围查询 O(n) O(log n) O(n)

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