rokevin
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
  • 二叉树

二叉树

二叉树(Binary Tree):每个节点最多有两个子节点(左子节点和右子节点)的树形结构。它是最基本的树形结构,节点间没有特定的顺序要求。

二叉树的DFS todo

前中后续遍历

  1. 递归
  2. 非递归(栈)

神级遍历 morris

二叉树全类型对比与 Java 实现

以下是常见二叉树类型的详细对比,包括定义、特点、所属类别、示例、关键性质、现实应用场景及 Java 代码示例:

一、基础分类二叉树

1. 普通二叉树(Binary Tree)

  • 定义:每个节点最多有两个子节点的树结构。

  • 特点:无特殊约束,结构自由。

  • 示例

    :

    plaintext

        1
       / \
      2   3
         /
        4
    
  • 关键性质:节点数 n≥0,高度 h≥0。

  • 应用:作为其他树结构的基础。

2. 完美二叉树(Perfect Binary Tree)

  • 定义:所有层节点数达到最大值,叶子节点在最后一层。

  • 特点:总节点数 n=2h+1−1(h 为高度)。

  • 示例

    :

    plaintext

          1
        /   \
       2     3
      / \   / \
     4   5 6   7
    
  • 关键性质:每层节点数为 2h,结构对称。

  • 应用:理论模型、并行计算。

3. 完全二叉树(Complete Binary Tree)

  • 定义:除最后一层外满,最后一层节点左对齐。

  • 特点:适合数组存储,父子关系通过下标计算。

  • 示例

    :

    plaintext

          1
        /   \
       2     3
      / \   /
     4   5 6
    
  • 关键性质:高度 h=⌊log2n⌋,最后一层可能不满。

  • 应用:二叉堆、堆排序。

4. 满二叉树(Full Binary Tree)

  • 定义:每个非叶子节点有两个子节点。

  • 特点:叶子节点数 = 非叶子节点数 + 1。

  • 示例

    :

    plaintext

          1
        /   \
       2     3
      / \
     4   5
    
  • 关键性质:总节点数为奇数。

  • 应用:理论模型。

二、搜索类二叉树

5. 二叉搜索树(BST, Binary Search Tree)

  • 定义:左子树 ≤ 根 ≤ 右子树,中序遍历有序。

  • 特点:平均操作 O(logn),可能退化为链表。

  • 示例

    :

    plaintext

          5
        /   \
       3     7
      / \   / \
     2   4 6   8
    
  • 关键性质:中序遍历结果为升序。

  • 应用:动态数据集合、查找表。

6. AVL 树(平衡二叉搜索树)

  • 定义:BST 的子类,每个节点的左右子树高度差 ≤ 1。

  • 特点:通过旋转维持平衡,高度始终 O(logn)。

  • 示例

    :

    plaintext

          5
        /   \
       3     7
      /     / \
     2     6   8
    
  • 关键性质:四种旋转操作(左旋、右旋、左右旋、右左旋)。

  • 应用:数据库索引、高效查找插入删除。

7. 红黑树(Red-Black Tree)

  • 定义:BST 的子类,通过颜色标记和规则约束维持近似平衡。

  • 特点:最长路径 ≤ 2 倍最短路径,插入 / 删除效率优于 AVL 树。

  • 关键规则

    :

    1. 节点为红色或黑色。
    2. 根节点和叶子节点(NIL)是黑色。
    3. 红色节点的子节点必须是黑色。
    4. 从任一节点到其每个叶子的路径包含相同数目的黑色节点。
  • 应用:Java TreeMap/TreeSet、Linux 内存管理。

8. 伸展树(Splay Tree)

  • 定义:BST 的子类,访问频繁的节点靠近根节点。
  • 特点:通过伸展操作(Splaying)将最近访问的节点移至根。
  • 关键性质:自适应优化,局部性原理提升效率。
  • 应用:缓存系统、垃圾回收算法。

9. 替罪羊树(Scapegoat Tree)

  • 定义:BST 的子类,在失衡时通过重构子树恢复平衡。
  • 特点:插入 / 删除后检查平衡因子,超过阈值则重构。
  • 关键性质:重构操作分摊时间复杂度 O(logn)。
  • 应用:需要稳定性能的场景。

三、其他特殊二叉树

10. 霍夫曼树(Huffman Tree)

  • 定义:带权路径长度(WPL)最小的二叉树。
  • 特点:权值越大的叶子离根越近,用于数据压缩。
  • 应用:JPEG、ZIP 等压缩算法。

11. 二叉堆(Binary Heap)

  • 定义:完全二叉树,满足堆性质(大根堆 / 小根堆)。
  • 特点:插入 / 删除 O(logn),适合优先队列。
  • 应用:任务调度、Dijkstra 算法。

12. 线段树(Segment Tree)

  • 定义:每个节点代表一个区间,用于高效处理区间查询。
  • 特点:查询、更新时间复杂度 O(logn)。
  • 应用:区间求和、区间最值查询。

四、Java 代码示例

1. AVL 树(平衡二叉搜索树)

java

public class AVLTree {
    static class Node {
        int val, height;
        Node left, right;
        Node(int val) {
            this.val = val;
            this.height = 1;
        }
    }

    private Node root;

    private int height(Node node) {
        return node == null ? 0 : node.height;
    }

    private int getBalance(Node node) {
        return node == null ? 0 : height(node.left) - height(node.right);
    }

    private Node rightRotate(Node y) {
        Node x = y.left;
        Node T2 = x.right;
        x.right = y;
        y.left = T2;
        y.height = Math.max(height(y.left), height(y.right)) + 1;
        x.height = Math.max(height(x.left), height(x.right)) + 1;
        return x;
    }

    private Node leftRotate(Node x) {
        Node y = x.right;
        Node T2 = y.left;
        y.left = x;
        x.right = T2;
        x.height = Math.max(height(x.left), height(x.right)) + 1;
        y.height = Math.max(height(y.left), height(y.right)) + 1;
        return y;
    }

    public void insert(int val) {
        root = insertRec(root, val);
    }

    private Node insertRec(Node node, int val) {
        if (node == null) return new Node(val);
        if (val < node.val) {
            node.left = insertRec(node.left, val);
        } else {
            node.right = insertRec(node.right, val);
        }

        node.height = 1 + Math.max(height(node.left), height(node.right));
        int balance = getBalance(node);

        if (balance > 1 && val < node.left.val) {
            return rightRotate(node);
        }

        if (balance < -1 && val > node.right.val) {
            return leftRotate(node);
        }

        if (balance > 1 && val > node.left.val) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }

        if (balance < -1 && val < node.right.val) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }

        return node;
    }
}

2. 红黑树(简化版)

java

public class RedBlackTree {
    private static final boolean RED = true;
    private static final boolean BLACK = false;

    static class Node {
        int val;
        Node left, right;
        boolean color;
        Node(int val) {
            this.val = val;
            this.color = RED;
        }
    }

    private Node root;

    private boolean isRed(Node node) {
        return node == null ? false : node.color == RED;
    }

    private Node rotateLeft(Node h) {
        Node x = h.right;
        h.right = x.left;
        x.left = h;
        x.color = h.color;
        h.color = RED;
        return x;
    }

    private Node rotateRight(Node h) {
        Node x = h.left;
        h.left = x.right;
        x.right = h;
        x.color = h.color;
        h.color = RED;
        return x;
    }

    private void flipColors(Node h) {
        h.color = RED;
        h.left.color = BLACK;
        h.right.color = BLACK;
    }

    public void insert(int val) {
        root = insert(root, val);
        root.color = BLACK;
    }

    private Node insert(Node h, int val) {
        if (h == null) return new Node(val);

        if (val < h.val) {
            h.left = insert(h.left, val);
        } else {
            h.right = insert(h.right, val);
        }

        if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h);
        if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
        if (isRed(h.left) && isRed(h.right)) flipColors(h);

        return h;
    }
}

3. 伸展树(Splay Tree)

java

public class SplayTree {
    static class Node {
        int val;
        Node left, right;
        Node(int val) { this.val = val; }
    }

    private Node root;

    private Node splay(Node root, int val) {
        if (root == null || root.val == val) {
            return root;
        }

        if (val < root.val) {
            if (root.left == null) return root;

            if (val < root.left.val) {
                root.left.left = splay(root.left.left, val);
                root = rotateRight(root);
            } else if (val > root.left.val) {
                root.left.right = splay(root.left.right, val);
                if (root.left.right != null) {
                    root.left = rotateLeft(root.left);
                }
            }

            return (root.left == null) ? root : rotateRight(root);
        } else {
            if (root.right == null) return root;

            if (val > root.right.val) {
                root.right.right = splay(root.right.right, val);
                root = rotateLeft(root);
            } else if (val < root.right.val) {
                root.right.left = splay(root.right.left, val);
                if (root.right.left != null) {
                    root.right = rotateRight(root.right);
                }
            }

            return (root.right == null) ? root : rotateLeft(root);
        }
    }

    private Node rotateRight(Node x) {
        Node y = x.left;
        x.left = y.right;
        y.right = x;
        return y;
    }

    private Node rotateLeft(Node x) {
        Node y = x.right;
        x.right = y.left;
        y.left = x;
        return y;
    }

    public void insert(int val) {
        if (root == null) {
            root = new Node(val);
            return;
        }

        root = splay(root, val);

        if (val < root.val) {
            Node newNode = new Node(val);
            newNode.left = root.left;
            newNode.right = root;
            root.left = null;
            root = newNode;
        } else if (val > root.val) {
            Node newNode = new Node(val);
            newNode.right = root.right;
            newNode.left = root;
            root.right = null;
            root = newNode;
        }
    }
}

五、关键性质对比表

树类型所属类别平衡条件时间复杂度特点应用场景
完美二叉树基础二叉树所有层节点数最大O(logn)结构对称,节点数 2h+1−1理论模型、并行计算
完全二叉树基础二叉树最后一层左对齐O(logn)适合数组存储二叉堆、堆排序
满二叉树基础二叉树非叶子节点有两个子节点O(h)叶子数 = 非叶子数 + 1理论模型
二叉搜索树搜索类无强制平衡平均 O(logn)中序遍历有序动态数据集合
AVL 树搜索类(BST 子类)左右子树高度差 ≤ 1O(logn)严格平衡,旋转维护数据库索引、高效查找
红黑树搜索类(BST 子类)最长路径 ≤ 2 倍最短路径O(logn)近似平衡,插入 / 删除效率高Java TreeMap、Linux 内存管理
伸展树搜索类(BST 子类)频繁访问的节点靠近根均摊 O(logn)自适应优化缓存系统、垃圾回收
替罪羊树搜索类(BST 子类)失衡时重构子树O(logn)重构操作分摊开销需要稳定性能的场景
霍夫曼树特殊应用带权路径长度最小O(nlogn)用于数据压缩JPEG、ZIP 压缩算法
二叉堆特殊应用完全二叉树 + 堆性质O(logn)优先队列实现任务调度、Dijkstra 算法
线段树特殊应用每个节点代表一个区间O(logn)高效区间查询区间求和、区间最值查询

六、总结

  1. 基础二叉树(完美、完全、满)是结构定义,用于理论模型和存储优化。

  2. 搜索类二叉树(BST 及其子类)通过有序性实现高效查找,AVL 树追求严格平衡,红黑树在效率和平衡间折中,伸展树利用局部性原理。

  3. 特殊应用二叉树(霍夫曼树、二叉堆、线段树)针对特定问题设计,如压缩、优先队列和区间查询。

  4. 选择建议

    :

    • 数据分布均匀且操作简单:BST
    • 需要严格平衡:AVL 树
    • 频繁插入删除:红黑树
    • 访问具有局部性:伸展树
    • 特定领域问题:选择对应专用树结构

通过理解各种二叉树的特性和适用场景,可以在实际开发中做出更优的数据结构选择。

六、总结对比表

树类型定义与核心特点关键性质典型应用场景时间复杂度
完美二叉树所有层节点数达到最大值,叶子在最后一层总节点数 2h+1−1理论模型、并行算法所有操作 O(h)
完全二叉树除最后一层外满,最后一层节点左对齐适合数组存储,父子关系通过下标计算二叉堆、堆排序插入 / 删除 O(logn)
满二叉树每个非叶子节点有两个子节点叶子数 = 非叶子数 + 1理论模型所有操作 O(h)
二叉搜索树左子树 ≤ 根 ≤ 右子树,中序遍历有序平均操作 O(logn),可能退化动态数据集合、查找表最坏 O(n)
平衡二叉树每个节点的左右子树高度差 ≤ 1通过旋转维持平衡,高度始终 O(logn)数据库索引、高效查找插入删除所有操作 O(logn)

七、选择建议

  • 需要严格对称结构:选择完美二叉树(如理论分析)。
  • 需要高效存储和访问:选择完全二叉树(如二叉堆)。
  • 需要有序性和动态操作:选择二叉搜索树(需注意避免退化)。
  • 需要严格平衡:选择平衡二叉树(如 AVL 树、红黑树)。
最近更新:: 2025/5/27 23:08
Contributors: luokaiwen