Skip to content

Implementations of AVL, Red-Black, and Huffman Trees

🌲 1. AVL Tree (Self-Balancing Binary Search Tree)

The core idea of an AVL tree:

Each node maintains a height. After insertion, rotations (left/right) are performed to maintain balance.

typescript
// AVL Tree in TypeScript

class AVLNode<T> {
  key: T;
  height: number;
  left: AVLNode<T> | null = null;
  right: AVLNode<T> | null = null;

  constructor(key: T) {
    this.key = key;
    this.height = 1;
  }
}

class AVLTree<T> {
  root: AVLNode<T> | null = null;

  private height(node: AVLNode<T> | null): number {
    return node ? node.height : 0;
  }

  private getBalance(node: AVLNode<T> | null): number {
    return node ? this.height(node.left) - this.height(node.right) : 0;
  }

  private rotateRight(y: AVLNode<T>): AVLNode<T> {
    const x = y.left!;
    const T2 = x.right;

    x.right = y;
    y.left = T2;

    y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;
    x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;

    return x;
  }

  private rotateLeft(x: AVLNode<T>): AVLNode<T> {
    const y = x.right!;
    const T2 = y.left;

    y.left = x;
    x.right = T2;

    x.height = Math.max(this.height(x.left), this.height(x.right)) + 1;
    y.height = Math.max(this.height(y.left), this.height(y.right)) + 1;

    return y;
  }

  insert(key: T): void {
    this.root = this._insert(this.root, key);
  }

  private _insert(node: AVLNode<T> | null, key: T): AVLNode<T> {
    if (!node) return new AVLNode(key);

    if (key < node.key) node.left = this._insert(node.left, key);
    else if (key > node.key) node.right = this._insert(node.right, key);
    else return node;

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

    if (balance > 1 && key < (node.left?.key ?? key)) return this.rotateRight(node); // LL
    if (balance < -1 && key > (node.right?.key ?? key)) return this.rotateLeft(node); // RR
    if (balance > 1 && key > (node.left?.key ?? key)) { // LR
      node.left = this.rotateLeft(node.left!);
      return this.rotateRight(node);
    }
    if (balance < -1 && key < (node.right?.key ?? key)) { // RL
      node.right = this.rotateRight(node.right!);
      return this.rotateLeft(node);
    }

    return node;
  }

  inorder(node = this.root): void {
    if (!node) return;
    this.inorder(node.left);
    console.log(node.key);
    this.inorder(node.right);
  }
}

// ✅ Example
const avl = new AVLTree<number>();
[10, 20, 30, 25, 28, 27].forEach(n => avl.insert(n));
avl.inorder(); // Outputs a sorted sequence
python
# AVL Tree in Python

class AVLNode:
    def __init__(self, key):
        self.key = key
        self.height = 1
        self.left = None
        self.right = None

class AVLTree:
    def __init__(self):
        self.root = None

    # 获取节点高度
    def _height(self, node):
        return node.height if node else 0

    # 获取平衡因子
    def _get_balance(self, node):
        return self._height(node.left) - self._height(node.right) if node else 0

    # 右旋
    def _rotate_right(self, y):
        x = y.left
        T2 = x.right

        x.right = y
        y.left = T2

        # 更新高度
        y.height = 1 + max(self._height(y.left), self._height(y.right))
        x.height = 1 + max(self._height(x.left), self._height(x.right))

        return x

    # 左旋
    def _rotate_left(self, x):
        y = x.right
        T2 = y.left

        y.left = x
        x.right = T2

        # 更新高度
        x.height = 1 + max(self._height(x.left), self._height(x.right))
        y.height = 1 + max(self._height(y.left), self._height(y.right))

        return y

    # 插入节点
    def insert(self, key):
        self.root = self._insert(self.root, key)

    def _insert(self, node, key):
        # 1. 执行标准BST插入
        if not node:
            return AVLNode(key)
        elif key < node.key:
            node.left = self._insert(node.left, key)
        elif key > node.key:
            node.right = self._insert(node.right, key)
        else:  # 不允许重复值
            return node

        # 2. 更新当前节点高度
        node.height = 1 + max(self._height(node.left), self._height(node.right))

        # 3. 获取平衡因子判断是否失衡
        balance = self._get_balance(node)

        # 4. 处理四种失衡情况
        # LL情况:左左失衡,右旋
        if balance > 1 and key < node.left.key:
            return self._rotate_right(node)
        # RR情况:右右失衡,左旋
        if balance < -1 and key > node.right.key:
            return self._rotate_left(node)
        # LR情况:左右失衡,先左旋后右旋
        if balance > 1 and key > node.left.key:
            node.left = self._rotate_left(node.left)
            return self._rotate_right(node)
        # RL情况:右左失衡,先右旋后左旋
        if balance < -1 and key < node.right.key:
            node.right = self._rotate_right(node.right)
            return self._rotate_left(node)

        return node

    # 中序遍历
    def inorder(self, node=None):
        if node is None:
            node = self.root
        return self._inorder(node)

    def _inorder(self, node):
        if not node:
            return
        self._inorder(node.left)
        print(node.key, end=' ')
        self._inorder(node.right)

if __name__ == "__main__":
    avl = AVLTree()
    for num in [10, 20, 30, 25, 28, 27]:
        avl.insert(num)
    avl.inorder()  # 输出有序序列:10 20 25 27 28 30
kotlin
// AVL Tree in Kotlin
class AVLNode(val key: Int) {
    var height = 1
    var left: AVLNode? = null
    var right: AVLNode? = null
}

class AVLTree {
    private var root: AVLNode? = null

    // 获取节点高度
    private fun height(node: AVLNode?): Int {
        return node?.height ?: 0
    }

    // 获取平衡因子
    private fun getBalance(node: AVLNode?): Int {
        return if (node == null) 0 else height(node.left) - height(node.right)
    }

    // 右旋
    private fun rotateRight(y: AVLNode): AVLNode {
        val x = y.left!!
        val t2 = x.right

        x.right = y
        y.left = t2

        // 更新高度
        y.height = 1 + maxOf(height(y.left), height(y.right))
        x.height = 1 + maxOf(height(x.left), height(x.right))

        return x
    }

    // 左旋
    private fun rotateLeft(x: AVLNode): AVLNode {
        val y = x.right!!
        val t2 = y.left

        y.left = x
        x.right = t2

        // 更新高度
        x.height = 1 + maxOf(height(x.left), height(x.right))
        y.height = 1 + maxOf(height(y.left), height(y.right))

        return y
    }

    // 插入节点
    fun insert(key: Int) {
        root = insert(root, key)
    }

    private fun insert(node: AVLNode?, key: Int): AVLNode {
        // 1. 执行标准BST插入
        if (node == null) {
            return AVLNode(key)
        } else if (key < node.key) {
            node.left = insert(node.left, key)
        } else if (key > node.key) {
            node.right = insert(node.right, key)
        } else { // 不允许重复值
            return node
        }

        // 2. 更新当前节点高度
        node.height = 1 + maxOf(height(node.left), height(node.right))

        // 3. 获取平衡因子判断是否失衡
        val balance = getBalance(node)

        // 4. 处理四种失衡情况
        // LL情况:左左失衡,右旋
        if (balance > 1 && key < node.left!!.key) {
            return rotateRight(node)
        }
        // RR情况:右右失衡,左旋
        if (balance < -1 && key > node.right!!.key) {
            return rotateLeft(node)
        }
        // LR情况:左右失衡,先左旋后右旋
        if (balance > 1 && key > node.left!!.key) {
            node.left = rotateLeft(node.left!!)
            return rotateRight(node)
        }
        // RL情况:右左失衡,先右旋后左旋
        if (balance < -1 && key < node.right!!.key) {
            node.right = rotateRight(node.right!!)
            return rotateLeft(node)
        }

        return node
    }

    // 中序遍历
    fun inorder() {
        inorder(root)
    }

    private fun inorder(node: AVLNode?) {
        if (node != null) {
            inorder(node.left)
            print("${node.key} ")
            inorder(node.right)
        }
    }
}

// 示例
fun main() {
    val avl = AVLTree()
    val numbers = listOf(10, 20, 30, 25, 28, 27)
    numbers.forEach { avl.insert(it) }
    avl.inorder()  // 输出有序序列:10 20 25 27 28 30
}

🔴 2. Red-Black Tree

Key points:

  • Nodes have a color (red/black)
  • Balance is maintained via rotations + recoloring
  • Satisfies the five properties of a red-black tree (root black, no consecutive red nodes, etc.)
typescript
// Red-Black Tree in TypeScript

enum Color { RED, BLACK }

class RBNode<T> {
  key: T;
  color: Color = Color.RED;
  left: RBNode<T> | null = null;
  right: RBNode<T> | null = null;
  parent: RBNode<T> | null = null;

  constructor(key: T) {
    this.key = key;
  }
}

class RedBlackTree<T> {
  root: RBNode<T> | null = null;

  private rotateLeft(x: RBNode<T>) { /* ... rotation logic ... */ }
  private rotateRight(y: RBNode<T>) { /* ... rotation logic ... */ }
  private fixInsert(z: RBNode<T>) { /* ... fix violations ... */ }

  insert(key: T) {
    const node = new RBNode(key);
    let y: RBNode<T> | null = null;
    let x = this.root;

    while (x) {
      y = x;
      if (node.key < x.key) x = x.left;
      else x = x.right;
    }

    node.parent = y;
    if (!y) this.root = node;
    else if (node.key < y.key) y.left = node;
    else y.right = node;

    this.fixInsert(node);
  }

  inorder(node = this.root): void {
    if (!node) return;
    this.inorder(node.left);
    console.log(`${node.key} (${node.color === Color.RED ? "R" : "B"})`);
    this.inorder(node.right);
  }
}

// ✅ Example
const rbt = new RedBlackTree<number>();
[10, 20, 30, 15, 25, 5].forEach(n => rbt.insert(n));
rbt.inorder();
python
# Red-Black Tree in Python
from enum import Enum

class Color(Enum):
    RED = 0
    BLACK = 1

class RBNode:
    def __init__(self, key):
        self.key = key
        self.color = Color.RED
        self.left = None
        self.right = None
        self.parent = None

class RedBlackTree:
    def __init__(self):
        self.root = None

    def rotate_left(self, x):
        y = x.right
        x.right = y.left
        if y.left:
            y.left.parent = x
        y.parent = x.parent

        if not x.parent:
            self.root = y
        elif x == x.parent.left:
            x.parent.left = y
        else:
            x.parent.right = y

        y.left = x
        x.parent = y

    def rotate_right(self, y):
        x = y.left
        y.left = x.right
        if x.right:
            x.right.parent = y
        x.parent = y.parent

        if not y.parent:
            self.root = x
        elif y == y.parent.left:
            y.parent.left = x
        else:
            y.parent.right = x

        x.right = y
        y.parent = x

    def fix_insert(self, z):
        while z.parent and z.parent.color == Color.RED:
            gp = z.parent.parent
            if not gp:
                break
            if z.parent == gp.left:
                uncle = gp.right
                if uncle and uncle.color == Color.RED:
                    z.parent.color = Color.BLACK
                    uncle.color = Color.BLACK
                    gp.color = Color.RED
                    z = gp
                else:
                    if z == z.parent.right:
                        z = z.parent
                        self.rotate_left(z)
                    z.parent.color = Color.BLACK
                    gp.color = Color.RED
                    self.rotate_right(gp)
            else:
                uncle = gp.left
                if uncle and uncle.color == Color.RED:
                    z.parent.color = Color.BLACK
                    uncle.color = Color.BLACK
                    gp.color = Color.RED
                    z = gp
                else:
                    if z == z.parent.left:
                        z = z.parent
                        self.rotate_right(z)
                    z.parent.color = Color.BLACK
                    gp.color = Color.RED
                    self.rotate_left(gp)
        self.root.color = Color.BLACK

    def insert(self, key):
        node = RBNode(key)
        y = None
        x = self.root

        while x:
            y = x
            if node.key < x.key:
                x = x.left
            else:
                x = x.right

        node.parent = y
        if not y:
            self.root = node
        elif node.key < y.key:
            y.left = node
        else:
            y.right = node

        self.fix_insert(node)

    def inorder(self, node=None):
        if node is None:
            node = self.root
        self._inorder(node)

    def _inorder(self, node):
        if not node:
            return
        self._inorder(node.left)
        color = "R" if node.color == Color.RED else "B"
        print(f"{node.key} ({color})", end=" ")
        self._inorder(node.right)

# 示例
if __name__ == "__main__":
    rbt = RedBlackTree()
    for n in [10, 20, 30, 15, 25, 5]:
        rbt.insert(n)
    rbt.inorder()
kotlin
// Red-Black Tree in Kotlin
enum class Color { RED, BLACK }

class RBNode<T : Comparable<T>>(val key: T) {
    var color: Color = Color.RED
    var left: RBNode<T>? = null
    var right: RBNode<T>? = null
    var parent: RBNode<T>? = null
}

class RedBlackTree<T : Comparable<T>> {
    private var root: RBNode<T>? = null

    private fun rotateLeft(x: RBNode<T>) {
        val y = x.right!!
        x.right = y.left
        y.left?.parent = x
        y.parent = x.parent

        if (x.parent == null) {
            root = y
        } else if (x == x.parent?.left) {
            x.parent?.left = y
        } else {
            x.parent?.right = y
        }

        y.left = x
        x.parent = y
    }

    private fun rotateRight(y: RBNode<T>) {
        val x = y.left!!
        y.left = x.right
        x.right?.parent = y
        x.parent = y.parent

        if (y.parent == null) {
            root = x
        } else if (y == y.parent?.left) {
            y.parent?.left = x
        } else {
            y.parent?.right = x
        }

        x.right = y
        y.parent = x
    }

    private fun fixInsert(z: RBNode<T>) {
        var current = z
        while (current.parent != null && current.parent?.color == Color.RED) {
            val gp = current.parent?.parent
            if (gp == null) break

            if (current.parent == gp.left) {
                val uncle = gp.right
                if (uncle != null && uncle.color == Color.RED) {
                    current.parent?.color = Color.BLACK
                    uncle.color = Color.BLACK
                    gp.color = Color.RED
                    current = gp
                } else {
                    if (current == current.parent?.right) {
                        current = current.parent!!
                        rotateLeft(current)
                    }
                    current.parent?.color = Color.BLACK
                    gp.color = Color.RED
                    rotateRight(gp)
                }
            } else {
                val uncle = gp.left
                if (uncle != null && uncle.color == Color.RED) {
                    current.parent?.color = Color.BLACK
                    uncle.color = Color.BLACK
                    gp.color = Color.RED
                    current = gp
                } else {
                    if (current == current.parent?.left) {
                        current = current.parent!!
                        rotateRight(current)
                    }
                    current.parent?.color = Color.BLACK
                    gp.color = Color.RED
                    rotateLeft(gp)
                }
            }
        }
        root?.color = Color.BLACK
    }

    fun insert(key: T) {
        val node = RBNode(key)
        var y: RBNode<T>? = null
        var x = root

        while (x != null) {
            y = x
            x = if (node.key < x.key) x.left else x.right
        }

        node.parent = y
        when {
            y == null -> root = node
            node.key < y.key -> y.left = node
            else -> y.right = node
        }

        fixInsert(node)
    }

    fun inorder() {
        inorder(root)
    }

    private fun inorder(node: RBNode<T>?) {
        if (node != null) {
            inorder(node.left)
            val color = if (node.color == Color.RED) "R" else "B"
            print("${node.key} ($color) ")
            inorder(node.right)
        }
    }
}

// 示例
fun main() {
    val rbt = RedBlackTree<Int>()
    listOf(10, 20, 30, 15, 25, 5).forEach { rbt.insert(it) }
    rbt.inorder()
}

🟡 3. Huffman Tree

Huffman trees are used to generate optimal codes for compression:

Repeatedly merge the two nodes with the smallest frequencies until only one node remains.

typescript
// Huffman Tree in TypeScript

class HuffmanNode {
  char?: string;
  freq: number;
  left: HuffmanNode | null = null;
  right: HuffmanNode | null = null;

  constructor(freq: number, char?: string) {
    this.freq = freq;
    this.char = char;
  }
}

class HuffmanTree {
  root: HuffmanNode | null = null;

  constructor(frequencies: Record<string, number>) {
    const nodes: HuffmanNode[] = Object.entries(frequencies)
      .map(([char, freq]) => new HuffmanNode(freq, char));

    while (nodes.length > 1) {
      nodes.sort((a, b) => a.freq - b.freq);
      const left = nodes.shift()!;
      const right = nodes.shift()!;
      const merged = new HuffmanNode(left.freq + right.freq);
      merged.left = left;
      merged.right = right;
      nodes.push(merged);
    }

    this.root = nodes[0];
  }

  generateCodes(node = this.root, code = "", result: Record<string, string> = {}): Record<string, string> {
    if (!node) return result;
    if (node.char) result[node.char] = code;
    this.generateCodes(node.left, code + "0", result);
    this.generateCodes(node.right, code + "1", result);
    return result;
  }
}

// ✅ Example
const freqs = { A: 5, B: 9, C: 12, D: 13, E: 16, F: 45 };
const huffman = new HuffmanTree(freqs);
const codes = huffman.generateCodes();
console.log("Huffman Codes:", codes);
python
# Huffman Tree in Python
class HuffmanNode:
    def __init__(self, freq: int, char: str = None):
        self.char = char
        self.freq = freq
        self.left = None
        self.right = None

class HuffmanTree:
    def __init__(self, frequencies: dict[str, int]):
        # 创建初始节点列表
        nodes = [HuffmanNode(freq, char) for char, freq in frequencies.items()]
        
        # 构建哈夫曼树
        while len(nodes) > 1:
            # 按频率排序
            nodes.sort(key=lambda x: x.freq)
            # 取出频率最小的两个节点
            left = nodes.pop(0)
            right = nodes.pop(0)
            # 合并为新节点
            merged = HuffmanNode(left.freq + right.freq)
            merged.left = left
            merged.right = right
            nodes.append(merged)
        
        self.root = nodes[0] if nodes else None
    
    # 生成哈夫曼编码
    def generate_codes(self) -> dict[str, str]:
        codes = {}
        self._generate_codes_recursive(self.root, "", codes)
        return codes
    
    def _generate_codes_recursive(self, node: HuffmanNode, current_code: str, codes: dict[str, str]) -> None:
        if not node:
            return
        # 如果是叶子节点,记录编码
        if node.char:
            codes[node.char] = current_code
        # 递归处理左右子树
        self._generate_codes_recursive(node.left, current_code + "0", codes)
        self._generate_codes_recursive(node.right, current_code + "1", codes)

# 示例
if __name__ == "__main__":
    freqs = {"A": 5, "B": 9, "C": 12, "D": 13, "E": 16, "F": 45}
    huffman = HuffmanTree(freqs)
    codes = huffman.generate_codes()
    print("Huffman Codes:", codes)
kotlin
// Huffman Tree in Kotlin
class HuffmanNode(
    val freq: Int,
    val char: Char? = null
) {
    var left: HuffmanNode? = null
    var right: HuffmanNode? = null
}

class HuffmanTree(frequencies: Map<Char, Int>) {
    private val root: HuffmanNode?

    init {
        // 创建初始节点列表
        val nodes = frequencies.map { (char, freq) -> HuffmanNode(freq, char) }.toMutableList()
        
        // 构建哈夫曼树
        while (nodes.size > 1) {
            // 按频率排序
            nodes.sortBy { it.freq }
            // 取出频率最小的两个节点
            val left = nodes.removeFirst()
            val right = nodes.removeFirst()
            // 合并为新节点
            val merged = HuffmanNode(left.freq + right.freq)
            merged.left = left
            merged.right = right
            nodes.add(merged)
        }
        
        root = if (nodes.isNotEmpty()) nodes[0] else null
    }

    // 生成哈夫曼编码
    fun generateCodes(): Map<Char, String> {
        val codes = mutableMapOf<Char, String>()
        generateCodesRecursive(root, "", codes)
        return codes
    }

    private fun generateCodesRecursive(
        node: HuffmanNode?,
        currentCode: String,
        codes: MutableMap<Char, String>
    ) {
        if (node == null) return
        // 如果是叶子节点,记录编码
        if (node.char != null) {
            codes[node.char] = currentCode
        }
        // 递归处理左右子树
        generateCodesRecursive(node.left, currentCode + "0", codes)
        generateCodesRecursive(node.right, currentCode + "1", codes)
    }
}

// 示例
fun main() {
    val freqs = mapOf('A' to 5, 'B' to 9, 'C' to 12, 'D' to 13, 'E' to 16, 'F' to 45)
    val huffman = HuffmanTree(freqs)
    val codes = huffman.generateCodes()
    println("Huffman Codes: $codes")
}

Sample output:

Huffman Codes: {
  F: '0',
  C: '100',
  D: '101',
  A: '1100',
  B: '1101',
  E: '111'
}

🧩 Comparison

Tree TypeUse CaseCore LogicTime ComplexityTypeScript File
AVL TreeFast lookupRotations to maintain strict balanceO(log n)avl-tree.ts
Red-Black TreeFast insert/deleteColors + rotations for approximate balanceO(log n)red-black-tree.ts
Huffman TreeOptimal codingMerge nodes with smallest frequencyO(n log n)huffman-tree.ts

Just something casual. Hope you like it. Built with VitePress