概念
BST 存在一个问题:
取决于你添加的节点数,树的一条边可能会非常深;
也就是说,树的一条分支会有很多层,而其他的分支却只有几层,
这会造成很大的性能问题
所以需要平衡二叉搜索树来解决这个问题
平衡二叉树的概念
- 在AVL 树中,需要对每个节点计算右子树高度(hr)和左子树高度(hl)之间的差值,该值(hr-hl)应为0、1 或 -1。
- 如果结果不是这三个值之一,则需要平衡该AVL 树。
这就是平衡因子的概念。
AVL的实现
- 我们可以扩展我们写的BST 类,只需要覆盖用来维持AVL 树平衡的方法,也就是insert、insertNode 和removeNode 方法。
- 所有其他的BST 方法将会被AVLTree 类继承。
1 平衡因子的计算
const BalanceFactor = {UNBALANCED_RIGHT: 1,SLIGHTLY_UNBALANCED_RIGHT: 2,BALANCED: 3,SLIGHTLY_UNBALANCED_LEFT: 4,UNBALANCED_LEFT: 5};
// 树的高度getNodeHeight(node) {if (!node) {return -1;}return Math.max(this.getNodeHeight(node.left), this.getNodeHeight(node.right)) + 1;}// 两个树的高度差getBalanceFactory(node) {let heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right);switch (heightDifference) {case -2: // 右边不平衡return BalanceFactory.UNBALANCE_RIGHT;case -1: // 右边有点点不平衡return BalanceFactory.SLIGHTLY_UNBALANCE_RIGHT;case 0: // 平衡return BalanceFactory.BALANCE;case 1: // 左边有点点不平衡return BalanceFactory.SLIGHTLY_UNBALANCE_LEFT;case 2: // 左边不平衡return BalanceFactory.UNBALANCE_LEFT;}}
2 平衡操作
- 左-左(LL):向右的单旋转
- 右-右(RR):向左的单旋转
- 左-右(LR):向右的双旋转(先LL 旋转,再RR 旋转)
- 右-左(RL):向左的双旋转(先RR 旋转,再LL 旋转)
向右的单旋转LL
这种情况出现于节点的左侧子节点的高度大于右侧子节点的高度时,并且左侧子节点也是平衡或左侧较重的,这个时候需要左子树放在上面。者就是所谓的右单旋转
假设向AVL 树插入节点5,这会造成树失衡(节点50-Y 高度为+2),需要恢复树的平衡。
- 保存不平衡树node的左子树temp
- node左子树替换为temp的右子树
- temp的右子树替换为改变后的node树



rotationLL(node) {let temp = node.left;node.left = temp.right;temp.right = node;return temp;}

RR:向左的单旋转
与LL情况相反。它出现于右侧子节点的高度大于左侧子节点的高度,并且右侧子节点也是平衡或右侧较重的
rotationRR(node) {let temp = node.right;node.right = temp.left;temp.left = node;return temp;}
向右的双旋转LR:Left-Right
- 这种情况出现于左侧子节点的高度大于右侧子节点的高度,并且左侧子节点右侧较重.
- 简而言之,左子树重了,左子树中的右子树也重了
- 在这种情况下,可以先对左侧子节点进行RR左旋转来修复,这样会形成LL的情况,然后再对不平衡的节点进行一个LL右旋转来修复

rotationLR(node) {node.left = this.rotationRR(node.left);return this.rotationLL(node);}
向左的双旋转RL: Right-Left
- 先对右子树进行LL右旋,整个树形成RR条件
- 再对整个树RR左旋

rotationRL(node) {node.right = this.rotationLL(node.right);return this.rotationRR(node);}
3 插入结点
插入方法和bst是一样的,不过还需要讨论不平衡的情况
- 如果在向左侧子树插入节点后树不平衡了,我们需要比较是否插入的键小于左侧子节点的键。如果是,我们要进行LL 旋转。否则,要进行LR 旋转。
- 如果在向右侧子树插入节点后树不平衡了,我们需要比较是否插入的键小于右侧子节点的键。如果是,我们要进行RR 旋转。否则,要进行RL 旋转。
insert(key) {this.root = this.insertNode(this.root, key);}insertNode(node, key) {// 像在BST 树中一样插入节点if (node == null) {return new Node(key);} else if (this.compareFn(key, node.key) === Compare.LESS_THAN) {node.left = this.insertNode(node.left, key);} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {node.right = this.insertNode(node.right, key);} else {return node; // 重复的键}// 如果需要,将树进行平衡操作const balanceFactor = this.getBalanceFactor(node);// 左不平衡if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {// 判断是否存在LR情况if (this.compareFn(key, node.left.key) === Compare.LESS_THAN) {node = this.rotationLL(node);} else {return this.rotationLR(node);}}// 右不平衡if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {if (this.compareFn(key, node.right.key) === Compare.BIGGER_THAN) {node = this.rotationRR(node);} else {return this.rotationRL(node);}}return node;}
4 删除结点
removeNode(node, key) {node = super.removeNode(node, key);if (node == null) {return node; // null,不需要进行平衡}// 检测树是否平衡const balanceFactor = this.getBalanceFactor(node);// 左不平衡if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {// 左子树状态const balanceFactorLeft = this.getBalanceFactor(node.left);// 如果是平衡(h = 0)或者有点不平衡(h = 1),LLif (balanceFactorLeft === BalanceFactor.BALANCED ||balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {return this.rotationLL(node);}// 如果不平衡(h = 2)LRif (balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {return this.rotationLR(node.left);}}// 右不平衡if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {// 右子树const balanceFactorRight = this.getBalanceFactor(node.right);if (balanceFactorRight === BalanceFactor.BALANCED ||balanceFactorRight === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {return this.rotationRR(node);}if (balanceFactorRight === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {return this.rotationRL(node.right);}}return node;}
完整代码
class Node {constructor(key) {this.key = key; // 节点值this.left = null; // 左侧子节点引用this.right = null; // 右侧子节点引用}}const Compare = {LESS_THAN: -1,BIGGER_THAN: 1};class BinarySearchTree {constructor() {this.root = null; // Node 类型的根节点 默认就是null}compareFn(a, b) {if (a === b) { //return 0;}return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; // 比较函数, a<b返回-1. 大于则返回正1}insert(key) {if (this.root == null) {this.root = new Node(key);} else {this.insertNode(this.root, key);}}insertNode(node, key) {if (this.compareFn(key, node.key) === Compare.LESS_THAN) {if (node.left == null) {node.left = new Node(key);} else {this.insertNode(node.left, key);}} else {if (node.right == null) {node.right = new Node(key);} else {this.insertNode(node.right, key);}}}inOrderTraverse(callback) {this.inOrderTraverseNode(this.root, callback);}inOrderTraverseNode(node, callback) {if (node != null) {this.inOrderTraverseNode(node.left, callback);callback(node.key);this.inOrderTraverseNode(node.right, callback);}}preOrderTraverse(callback) {this.preOrderTraverseNode(this.root, callback);}preOrderTraverseNode(node, callback) {if (node != null) {callback(node.key);this.preOrderTraverseNode(node.left, callback);this.preOrderTraverseNode(node.right, callback);}}postOrderTraverse(callback) {this.postOrderTraverseNode(this.root, callback);}postOrderTraverseNode(node, callback) {if (node != null) {this.postOrderTraverseNode(node.left, callback);this.postOrderTraverseNode(node.right, callback);callback(node.key);}}min() {return this.minNode(this.root);}minNode(node) {let current = node;while (current != null && current.left != null) {current = current.left;}return current;}max() {return this.maxNode(this.root);}maxNode(node) {let current = node;while (current != null && current.right != null) {current = current.right;}return current;}search(key) {return this.searchNode(this.root, key);}searchNode(node, key) {if (node == null) {return false;}if (this.compareFn(key, node.key) === Compare.LESS_THAN) {return this.searchNode(node.left, key);} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {return this.searchNode(node.right, key);} else {return true;}}remove(key) {this.root = this.removeNode(this.root, key);}removeNode(node, key) {if (node == null) {return null;}if (this.compareFn(key, node.key) === Compare.LESS_THAN) {node.left = this.removeNode(node.left, key);return node;} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {node.right = this.removeNode(node.right, key);return node;} else {// 键等于node.key// 第一种情况if (node.left == null && node.right == null) {node = null;return node;}// 第二种情况if (node.left == null) {node = node.right;return node;} else if (node.right == null) {node = node.left;return node;}// 第三种情况const aux = this.minNode(node.right);node.key = aux.key;node.right = this.removeNode(node.right, aux.key);return node;}}}const BalanceFactor = {UNBALANCED_RIGHT: 1,SLIGHTLY_UNBALANCED_RIGHT: 2,BALANCED: 3,SLIGHTLY_UNBALANCED_LEFT: 4,UNBALANCED_LEFT: 5};class AVLTree extends BinarySearchTree {constructor() {super();this.root = null;}getNodeHeight(node) {if (node == null) {return -1;}return Math.max(this.getNodeHeight(node.left), this.getNodeHeight(node.right)) + 1;}getBalanceFactor(node) {const heightDifference = this.getNodeHeight(node.left) -this.getNodeHeight(node.right);switch (heightDifference) {case -2:return BalanceFactor.UNBALANCED_RIGHT;case -1:return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT;case 1:return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT;case 2:return BalanceFactor.UNBALANCED_LEFT;default:return BalanceFactor.BALANCED;}}rotationLL(node) {const tmp = node.left;node.left = tmp.right;tmp.right = node;return tmp;}rotationRR(node) {const tmp = node.right;node.right = tmp.left;tmp.left = node;return tmp;}rotationLR(node) {node.left = this.rotationRR(node.left);return this.rotationLL(node);}rotationRL(node) {node.right = this.rotationLL(node.right);return this.rotationRR(node);}insert(key) {this.root = this.insertNode(this.root, key);}insertNode(node, key) {// 像在BST 树中一样插入节点if (node == null) {return new Node(key);} else if (this.compareFn(key, node.key) === Compare.LESS_THAN) {node.left = this.insertNode(node.left, key);} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {node.right = this.insertNode(node.right, key);} else {return node; // 重复的键}// 如果需要,将树进行平衡操作const balanceFactor = this.getBalanceFactor(node);if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {if (this.compareFn(key, node.left.key) === Compare.LESS_THAN) {node = this.rotationLL(node);} else {return this.rotationLR(node);}}if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {if (this.compareFn(key, node.right.key) === Compare.BIGGER_THAN) {node = this.rotationRR(node);} else {return this.rotationRL(node);}}return node;}removeNode(node, key) {node = super.removeNode(node, key);if (node == null) {return node; // null,不需要进行平衡}// 检测树是否平衡const balanceFactor = this.getBalanceFactor(node);// 左不平衡if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {// 左子树状态const balanceFactorLeft = this.getBalanceFactor(node.left);// 如果是平衡(h = 0)或者有点不平衡(h = 1),LLif (balanceFactorLeft === BalanceFactor.BALANCED ||balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {return this.rotationLL(node);}// 如果不平衡(h = 2)LRif (balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {return this.rotationLR(node.left);}}// 右不平衡if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {// 右子树const balanceFactorRight = this.getBalanceFactor(node.right);if (balanceFactorRight === BalanceFactor.BALANCED ||balanceFactorRight === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {return this.rotationRR(node);}if (balanceFactorRight === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {return this.rotationRL(node.right);}}return node;}}let avl = new AVLTree();avl.insert(70);avl.insert(50);avl.insert(80);avl.insert(72);avl.insert(90);avl.insert(75);avl.remove(70);avl.remove(50);console.log(avl);
