【JavaScript数据结构】平衡二叉搜索树

62 阅读2分钟

AVL树

平衡二叉搜索树是一种自平衡的二叉搜索树,其中任何节点的两个子树的高度差最多为1。其中最常见的平衡二叉搜索树是AVL树。

定义AVL树节点:

class AVLTreeNode {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
    this.height = 1;  // 默认高度为1
  }
}

AVL树的定义及其操作:

class AVLTree {
  constructor() {
    this.root = null;
  }

  // 获取节点的高度
  _getHeight(node) {
    return node ? node.height : 0;
  }

  // 获取节点的平衡因子
  _getBalanceFactor(node) {
    return this._getHeight(node.left) - this._getHeight(node.right);
  }

  // 右旋转
  _rotateRight(y) {
    const x = y.left;
    const T3 = x.right;

    x.right = y;
    y.left = T3;

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

    return x;
  }

  // 左旋转
  _rotateLeft(z) {
    const y = z.right;
    const T2 = y.left;

    y.left = z;
    z.right = T2;

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

    return y;
  }

  // 插入节点
  insert(value) {
    this.root = this._insertNode(this.root, value);
  }

  _insertNode(node, value) {
    if (!node) return new AVLTreeNode(value);

    // 正常的BST插入
    if (value < node.value) {
      node.left = this._insertNode(node.left, value);
    } else if (value > node.value) {
      node.right = this._insertNode(node.right, value);
    } else {
      return node;
    }

    // 更新高度
    node.height = 1 + Math.max(this._getHeight(node.left), this._getHeight(node.right));

    // 获取平衡因子检查是否失衡
    let balance = this._getBalanceFactor(node);

    // 进行旋转操作,以保持树的平衡

    // Left Heavy
    if (balance > 1) {
      // Left Right Heavy
      if (value > node.left.value) {
        node.left = this._rotateLeft(node.left);
      }
      // Left Left Heavy
      return this._rotateRight(node);
    }

    // Right Heavy
    if (balance < -1) {
      // Right Left Heavy
      if (value < node.right.value) {
        node.right = this._rotateRight(node.right);
      }
      // Right Right Heavy
      return this._rotateLeft(node);
    }

    return node;
  }

  // ... 其他操作如删除、查找可以参照普通的BST进行实现,但需要加入平衡的操作。
}

##红黑树 红黑树是一种自平衡二叉搜索树,每个节点都有一个颜色属性,红色或黑色。红黑树必须满足以下属性:

  1. 节点是红色或黑色。
  2. 根节点是黑色。
  3. 所有叶子(通常为NIL或空节点)是黑色。
  4. 如果一个红色节点有子节点,那么子节点必须是黑色。
  5. 从任何节点到其所有后代叶子的路径都包含相同数量的黑色节点。

以下是一个简化版的红黑树实现:

const RED = true;
const BLACK = false;

class TreeNode {
    constructor(value, color, left=null, right=null) {
        this.value = value;
        this.color = color; // 默认红色
        this.left = left;
        this.right = right;
        this.parent = null;
    }
}

class RedBlackTree {
    constructor() {
        this.NIL_LEAF = new TreeNode(null, BLACK);
        this.root = this.NIL_LEAF;
    }

    isRed(node) {
        return node.color === RED;
    }

    rotateLeft(node) {
        let tmp = node.right;
        node.right = tmp.left;
        if (tmp.left !== this.NIL_LEAF) {
            tmp.left.parent = node;
        }
        tmp.parent = node.parent;
        if (!node.parent) {
            this.root = tmp;
        } else if (node === node.parent.left) {
            node.parent.left = tmp;
        } else {
            node.parent.right = tmp;
        }
        tmp.left = node;
        node.parent = tmp;
    }

    rotateRight(node) {
        let tmp = node.left;
        node.left = tmp.right;
        if (tmp.right !== this.NIL_LEAF) {
            tmp.right.parent = node;
        }
        tmp.parent = node.parent;
        if (!node.parent) {
            this.root = tmp;
        } else if (node === node.parent.left) {
            node.parent.left = tmp;
        } else {
            node.parent.right = tmp;
        }
        tmp.right = node;
        node.parent = tmp;
    }

    insert(value) {
        let node = new TreeNode(value, RED, this.NIL_LEAF, this.NIL_LEAF);
        this._insertNode(node);
    }

    _insertNode(node) {
        // ... 标准的BST插入操作,同时维护父节点信息

        // 调整红黑树平衡
        this.fixInsert(node);
    }

    fixInsert(node) {
        let parentNode;
        while (node !== this.root && this.isRed(node.parent)) {
            parentNode = node.parent.parent;
            if (parentNode.left === node.parent) {
                let uncle = parentNode.right;
                if (this.isRed(uncle)) {
                    // Case 1: 叔叔节点也是红色
                    node.parent.color = BLACK;
                    uncle.color = BLACK;
                    parentNode.color = RED;
                    node = parentNode;
                } else {
                    if (node === node.parent.right) {
                        // Case 2: node是一个右子节点
                        node = node.parent;
                        this.rotateLeft(node);
                    }
                    // Case 3: node是一个左子节点
                    node.parent.color = BLACK;
                    parentNode.color = RED;
                    this.rotateRight(parentNode);
                }
            } else {
                // ... 上面代码的镜像操作,此时node在右子树
            }
        }
        this.root.color = BLACK;
    }

    // ... 还有其他操作,如删除、查找等
}