返回

技术指南:揭秘前端算法入门之路(手撕AVL树)

前端

二叉排序树(Binary Search Tree,BST),也称二叉查找树或二叉搜索树,是一种常见的树形数据结构,具有以下特性:

  • 左子树上的所有键值小于其父节点的键值。
  • 右子树上的所有键值大于其父节点的键值。
  • 左、右子树也是二叉排序树。

二叉排序树常用于解决与排名相关的检索需求,例如查找某个元素在集合中的位置或查找某个元素的前驱或后继。

AVL树(Adelson-Velsky and Landis Tree)是平衡二叉排序树的一种,其特点是左右子树的高度差至多为1,这样可以保证树的插入和删除操作的时间复杂度为O(log n)。

AVL树的插入和删除操作都比较复杂,但可以保证树的平衡性。AVL树常用于需要频繁插入和删除元素的场景。

现在让我们手撕一个AVL树。

1. AVL树的节点结构

class AVLNode {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
    this.height = 1;
  }
}

2. 计算节点的高度

AVLNode.prototype.getHeight = function () {
  return Math.max(this.left ? this.left.height : 0, this.right ? this.right.height : 0) + 1;
};

3. 计算节点的平衡因子

AVLNode.prototype.getBalanceFactor = function () {
  return (this.left ? this.left.height : 0) - (this.right ? this.right.height : 0);
};

4. 插入元素

AVLTree.prototype.insert = function (value) {
  const newNode = new AVLNode(value);
  this.root = this._insert(newNode, this.root);
};

AVLTree.prototype._insert = function (newNode, node) {
  if (!node) {
    return newNode;
  }

  if (value < node.value) {
    node.left = this._insert(newNode, node.left);
  } else if (value > node.value) {
    node.right = this._insert(newNode, node.right);
  } else {
    throw new Error('Duplicate value');
  }

  node.height = node.getHeight();
  const balanceFactor = node.getBalanceFactor();

  if (balanceFactor > 1) {
    if (value < node.left.value) {
      return this._rightRotate(node);
    } else {
      return this._leftRightRotate(node);
    }
  } else if (balanceFactor < -1) {
    if (value > node.right.value) {
      return this._leftRotate(node);
    } else {
      return this._rightLeftRotate(node);
    }
  }

  return node;
};

5. 删除元素

AVLTree.prototype.remove = function (value) {
  this.root = this._remove(value, this.root);
};

AVLTree.prototype._remove = function (value, node) {
  if (!node) {
    return null;
  }

  if (value < node.value) {
    node.left = this._remove(value, node.left);
  } else if (value > node.value) {
    node.right = this._remove(value, node.right);
  } else {
    if (!node.left) {
      return node.right;
    } else if (!node.right) {
      return node.left;
    } else {
      const minValueNode = this._findMinValueNode(node.right);
      node.value = minValueNode.value;
      node.right = this._remove(minValueNode.value, node.right);
    }
  }

  node.height = node.getHeight();
  const balanceFactor = node.getBalanceFactor();

  if (balanceFactor > 1) {
    if (node.left.getBalanceFactor() < 0) {
      return this._leftRightRotate(node);
    } else {
      return this._rightRotate(node);
    }
  } else if (balanceFactor < -1) {
    if (node.right.getBalanceFactor() > 0) {
      return this._rightLeftRotate(node);
    } else {
      return this._leftRotate(node);
    }
  }

  return node;
};

6. 旋转操作

AVLTree.prototype._rightRotate = function (node) {
  const leftNode = node.left;
  node.left = leftNode.right;
  leftNode.right = node;

  node.height = node.getHeight();
  leftNode.height = leftNode.getHeight();

  return leftNode;
};

AVLTree.prototype._leftRotate = function (node) {
  const rightNode = node.right;
  node.right = rightNode.left;
  rightNode.left = node;

  node.height = node.getHeight();
  rightNode.height = rightNode.getHeight();

  return rightNode;
};

AVLTree.prototype._leftRightRotate = function (node) {
  node.left = this._leftRotate(node.left);
  return this._rightRotate(node);
};

AVLTree.prototype._rightLeftRotate = function (node) {
  node.right = this._rightRotate(node.right);
  return this._leftRotate(node);
};

7. 查询元素

AVLTree.prototype.search = function (value) {
  return this._search(value, this.root);
};

AVLTree.prototype._search = function (value, node) {
  if (!node) {
    return null;
  }

  if (value < node.value) {
    return this._search(value, node.left);
  } else if (value > node.value) {
    return this._search(value, node.right);
  } else {
    return node;
  }
};

8. 查找最小值节点

AVLTree.prototype._findMinValueNode = function (node) {
  while (node.left) {
    node = node.left;
  }

  return node;
};

9. 查找最大值节点

AVLTree.prototype._findMaxValueNode = function (node) {
  while (node.right) {
    node = node.right;
  }

  return node;
};

10. 获取树的高度

AVLTree.prototype.getHeight = function () {
  return this.root ? this.root.height : 0;
};