建议先阅读: A 容器 Container, B 栈 Stack, F 队列 Queue


原理

树(Tree)是一种非线性层次结构,由节点和边组成。二叉树每个节点最多有两个子节点。

基本术语

  • 根节点(Root): 树的顶端,无父节点
  • 叶子节点(Leaf): 无子节点的节点
  • 深度(Depth): 从根到该节点的路径长度
  • 高度(Height): 从该节点到最远叶子的路径长度

二叉树的四种遍历

遍历方式顺序说明
前序遍历 Pre-order根 -> 左 -> 右复制树、前缀表达式
中序遍历 In-order左 -> 根 -> 右BST 有序输出
后序遍历 Post-order左 -> 右 -> 根释放内存、后缀表达式
层序遍历 Level-order逐层从左到右BFS

二叉搜索树(BST)

性质:左子树所有节点 < 根 < 右子树所有节点。

操作平均最坏说明
查找O(log n)O(n)退化为链表时 O(n)
插入O(log n)O(n)同上
删除O(log n)O(n)同上

AVL 树

AVL 是自平衡 BST,任意节点左右子树高度差 <= 1(平衡因子 BF = 左高 - 右高,BF ∈ {-1, 0, 1})。

四种旋转(图中红色节点为失衡节点,蓝色为旋转轴):

flowchart TD
    subgraph LL["LL 右旋"]
        LL1["失衡节点 10\nBF=2\n/ \\\n5   nil\n/\\\n3 7"] --> LL2["右旋后\n5\n/\\\n3  10\n  /\\\n 7  nil"]
    end
    subgraph RR["RR 左旋"]
        RR1["失衡节点 10\nBF=-2\n/ \\\nnil 15\n   /\\\n  12 20"] --> RR2["左旋后\n15\n/\\\n10  20\n/\\\nnil 12"]
    end
flowchart TD
    subgraph LR["LR 先左旋后右旋"]
        LR1["失衡节点 10\nBF=2\n/\\\n5  nil\n/\\\n3  7\n   /\\\n  6  8"] --> LR2["左旋 5\n得到 LL 情形"]
        LR2 --> LR3["右旋 10\n得到平衡树"]
    end
    subgraph RL["RL 先右旋后左旋"]
        RL1["失衡节点 10\nBF=-2\n/\\\nnil 15\n   /\\\n  12 20\n  /\\\n 11 13"] --> RL2["右旋 15\n得到 RR 情形"]
        RL2 --> RL3["左旋 10\n得到平衡树"]
    end

AVL 高度 ≤ 1.44 * log(n),保证查找/插入/删除均为 O(log n)。


实现

BST

#include <stdlib.h>
 
typedef struct BSTNode {
    int data;
    struct BSTNode* left;
    struct BSTNode* right;
} BSTNode;
 
typedef struct {
    BSTNode* root;
} BST;
 
BSTNode* bst_create_node(int val) {
    BSTNode* node = malloc(sizeof(BSTNode));
    node->data = val;
    node->left = NULL;
    node->right = NULL;
    return node;
}
 
static BSTNode* bst_insert_rec(BSTNode* node, int val) {
    if (!node) return bst_create_node(val);
    if (val < node->data)
        node->left = bst_insert_rec(node->left, val);
    else if (val > node->data)
        node->right = bst_insert_rec(node->right, val);
    return node;
}
 
void bst_insert(BST* t, int val) {
    t->root = bst_insert_rec(t->root, val);
}
 
static BSTNode* bst_search_rec(BSTNode* node, int val) {
    if (!node || node->data == val) return node;
    if (val < node->data) return bst_search_rec(node->left, val);
    return bst_search_rec(node->right, val);
}
 
int bst_find(BST* t, int val) {
    return bst_search_rec(t->root, val) != NULL;
}
 
static BSTNode* bst_find_min(BSTNode* node) {
    while (node && node->left) node = node->left;
    return node;
}
 
static BSTNode* bst_remove_rec(BSTNode* node, int val) {
    if (!node) return NULL;
    if (val < node->data)
        node->left = bst_remove_rec(node->left, val);
    else if (val > node->data)
        node->right = bst_remove_rec(node->right, val);
    else {
        if (!node->left) {
            BSTNode* tmp = node->right;
            free(node);
            return tmp;
        }
        if (!node->right) {
            BSTNode* tmp = node->left;
            free(node);
            return tmp;
        }
        BSTNode* min_node = bst_find_min(node->right);
        node->data = min_node->data;
        node->right = bst_remove_rec(node->right, min_node->data);
    }
    return node;
}
 
void bst_remove(BST* t, int val) {
    t->root = bst_remove_rec(t->root, val);
}
 
static void bst_destroy_rec(BSTNode* node) {
    if (!node) return;
    bst_destroy_rec(node->left);
    bst_destroy_rec(node->right);
    free(node);
}
 
void bst_destroy(BST* t) {
    bst_destroy_rec(t->root);
    t->root = NULL;
}

AVL 树

#include <stdlib.h>
 
typedef struct AVLNode {
    int data;
    int height;
    struct AVLNode* left;
    struct AVLNode* right;
} AVLNode;
 
typedef struct {
    AVLNode* root;
} AVLTree;
 
static int avl_height(AVLNode* n) { return n ? n->height : 0; }
static int avl_bf(AVLNode* n) {
    return n ? avl_height(n->left) - avl_height(n->right) : 0;
}
static void avl_update_height(AVLNode* n) {
    int lh = avl_height(n->left);
    int rh = avl_height(n->right);
    n->height = 1 + (lh > rh ? lh : rh);
}
 
static AVLNode* avl_right_rotate(AVLNode* y) {
    AVLNode* x = y->left;
    AVLNode* T2 = x->right;
    x->right = y;
    y->left = T2;
    avl_update_height(y);
    avl_update_height(x);
    return x;
}
 
static AVLNode* avl_left_rotate(AVLNode* x) {
    AVLNode* y = x->right;
    AVLNode* T2 = y->left;
    y->left = x;
    x->right = T2;
    avl_update_height(x);
    avl_update_height(y);
    return y;
}
 
AVLNode* avl_create_node(int val) {
    AVLNode* node = malloc(sizeof(AVLNode));
    node->data = val;
    node->height = 1;
    node->left = NULL;
    node->right = NULL;
    return node;
}
 
static AVLNode* avl_insert_rec(AVLNode* node, int val) {
    if (!node) return avl_create_node(val);
    if (val < node->data)
        node->left = avl_insert_rec(node->left, val);
    else if (val > node->data)
        node->right = avl_insert_rec(node->right, val);
    else
        return node;
 
    avl_update_height(node);
    int bf = avl_bf(node);
 
    // LL
    if (bf > 1 && val < node->left->data)
        return avl_right_rotate(node);
    // RR
    if (bf < -1 && val > node->right->data)
        return avl_left_rotate(node);
    // LR
    if (bf > 1 && val > node->left->data) {
        node->left = avl_left_rotate(node->left);
        return avl_right_rotate(node);
    }
    // RL
    if (bf < -1 && val < node->right->data) {
        node->right = avl_right_rotate(node->right);
        return avl_left_rotate(node);
    }
    return node;
}
 
void avl_insert(AVLTree* t, int val) {
    t->root = avl_insert_rec(t->root, val);
}
 
static AVLNode* avl_find_min(AVLNode* node) {
    while (node && node->left) node = node->left;
    return node;
}
 
static AVLNode* avl_remove_rec(AVLNode* node, int val) {
    if (!node) return NULL;
    if (val < node->data)
        node->left = avl_remove_rec(node->left, val);
    else if (val > node->data)
        node->right = avl_remove_rec(node->right, val);
    else {
        if (!node->left || !node->right) {
            AVLNode* tmp = node->left ? node->left : node->right;
            free(node);
            return tmp;
        }
        AVLNode* min_node = avl_find_min(node->right);
        node->data = min_node->data;
        node->right = avl_remove_rec(node->right, min_node->data);
    }
    if (!node) return NULL;
 
    avl_update_height(node);
    int bf = avl_bf(node);
 
    // LL
    if (bf > 1 && avl_bf(node->left) >= 0)
        return avl_right_rotate(node);
    // LR
    if (bf > 1 && avl_bf(node->left) < 0) {
        node->left = avl_left_rotate(node->left);
        return avl_right_rotate(node);
    }
    // RR
    if (bf < -1 && avl_bf(node->right) <= 0)
        return avl_left_rotate(node);
    // RL
    if (bf < -1 && avl_bf(node->right) > 0) {
        node->right = avl_right_rotate(node->right);
        return avl_left_rotate(node);
    }
    return node;
}
 
void avl_remove(AVLTree* t, int val) {
    t->root = avl_remove_rec(t->root, val);
}
 
static void avl_destroy_rec(AVLNode* node) {
    if (!node) return;
    avl_destroy_rec(node->left);
    avl_destroy_rec(node->right);
    free(node);
}
 
void avl_destroy(AVLTree* t) {
    avl_destroy_rec(t->root);
    t->root = NULL;
}

应用场景

  • 文件系统: 目录树,用多叉树表示
  • 表达式树: 编译器解析数学表达式为语法树
  • 数据库索引: BST/AVL/红黑树/B+树
  • 字典序存储: BST 中序遍历即有序输出

练习

题号题目难度知识点
P3369普通平衡树提高BST/AVL 基本操作
P1364医院设置普及树的遍历、带权路径
P1030求先序排列普及遍历序列重建树