树
数据结构
相关术语
- 位于树顶部的节点叫作根节点
- 至少有一个子节点的节点称为内部节点
- 没有子元素的节点称为外部节点或叶节点
- 子树由节点和它的后代构成
- 节点的深度取决于它的祖先节点的数量
- 树的高度取决于所有节点深度的最大值。一棵树也可以被分解成层级,根节点在第 0 层。
二叉树
二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。二叉搜索树(BST)是二叉树的一种,但是只允许在左侧节点存储(比父节点)小的值,在右侧节点存储(比父节点)大的值。
class Node {
constructor() {
this.key = key;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor(compareFn = defaultCompare) {
this.compareFn = compareFn;
this.root = null;
}
insert(key) {
if (this.root == null) {
this.root = new Node(key);
} else {
this.insertNode(this.root, key);
}
}
insertNode(node, key) {
if (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(cb) {
this.inOrderTraverseNode(this.root, cb);
}
inOrderTraverseNode(node, cb) {
if (node != null) {
this.inOrderTraverseNode(node.left, cb);
cb(node.key);
this.inOrderTraverseNode(node.right, cb);
}
}
// 先序遍历
preOrderTraverse(cb) {
this.preOrderTraverseNode(this.root, cb);
}
preOrderTraverseNode(node, cb) {
if (node != null) {
cb(node.key);
this.preOrderTraverseNode(node.left, cb);
this.preOrderTraverseNode(node.right, cb);
}
}
// 后续遍历
postOrderTraverse(cb) {
this.postOrderTraverseNode(this.root, cb);
}
postOrderTraverseNode(node, cb) {
if (node != null) {
this.postOrderTraverseNode(node.left, cb);
this.postOrderTraverseNode(node.right, cb);
cb(node.key);
}
}
// 搜索最小值
min() {
return this.miniNode(this.root);
}
miniNode(node) {
let current = node;
while(current != null && node.left != null) {
current = current.left;
}
return current;
}
// 最大值
max() {
return this.maxNode(this.root);
}
maxNode(node) {
let current = node;
while(current != null && node.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 {
// 无子节点
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.miniNode(node.right);
node.key = aux.key;
node.right = this.removeNode(node.right, aux.key);
return node;
}
}
}
自平衡树
Adelson-Velskii-Landi 树( AVL 树)是一种自平衡二叉搜索树,意思是任何一个节点左右两侧子树的高度之差最多为 1。在 AVL 树中,需要对每个节点计算右子树高度( hr)和左子树高度( hl)之间的差值,该值( hr- hl)应为 0、 1 或1。如果结果不是这三个值之一,则需要平衡该 AVL 树。这就是平衡因子的概念。
平衡操作——AVL 旋转
- 左-左(LL):向右的单旋转
- 右-右(RR):向左的单旋转
- 左-右(LR):向右的双旋转(先 LL 旋转,再 RR 旋转)
- 右-左(RL):向左的双旋转(先 RR 旋转,再 LL 旋转)
const BalanceFactor = {
UNBALANCED_RIGHT: 1,
SLIGHTLY_UNBALANCED_RIGHT: 2,
BALANCED: 3,
SLIGHTLY_UNBALANCED_LEFT: 4,
UNBALANCED_LEFT: 5
};
class AVLTree extends BinarySearchTree {
constructor(compareFn = defaultCompare) {
super(compareFn);
this.compareFn = compareFn;
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;
}
const balanceFactor = this.getBalanceFactor(node);
if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {
const balanceFactorLeft = this.getBalanceFactor(node.left);
if (balanceFactorLeft === BalanceFactor.BALANCED ||
balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {
return this.rotationLL(node);
}
if (balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {
return this.rotationLR(node);
}
}
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);
}
}
return node;
}
}
红黑树
红黑树也是一个自平衡二叉搜索树。如果插入和删除频率较低,AVL 树比红黑树更好。
红黑树定义规则
- 每个节点不是红的就是黑的
- 树的根节点是黑的
- 所有叶节点都是黑的(用 NULL 引用表示的节点)
- 如果一个节点是红的,那么它的两个子节点都是黑的
- 不能有两个相邻的红节点,一个红节点不能有红的父节点或子节点
- 从给定的节点到它的后代节点( NULL 叶节点)的所有路径包含相同数量的黑色节点
旋转和颜色变换规则
变颜色:当前节点的父亲是红色,且它的祖父节点的另一个子节点(叔叔节点)也是红色
- 把父节点设为黑色
- 把叔叔节点也设为黑色
- 把祖父节点设为红色
- 把指针定义到祖父节点设为当前要操作的,分析节点变换规则
- 左旋:当前父亲节点是红色,叔叔节点是黑色,且当前节点是右子树,左旋以父节点作为左旋
右旋:当前父节点是红色,叔叔是黑色的时候,且当前的节点是左子树
- 把父节点变为黑色
- 将祖父节点变为红色
- 以祖父节点旋转
class RedBlackNode extends Node {
constructor(key) {
super(key);
this.key = key;
this.color = Colors.RED;
this.parent = null;
}
isRed() {
return this.color === Colors.RED;
}
}
class RedBlackTree extends BinarySearchTree {
constructor(compareFn = defaultCompare) {
super(compareFn);
this.compareFn = compareFn;
this.root = null;
}
insert(key: T) {
if (this.root == null) {
this.root = new RedBlackNode(key);
this.root.color = Colors.BLACK;
} else {
const newNode = this.insertNode(this.root, key);
this.fixTreeProperties(newNode);
}
}
insertNode(node, key) {
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
if (node.left == null) {
node.left = new RedBlackNode(key);
node.left.parent = node;
return node.left;
} else {
return this.insertNode(node.left, key);
}
} else if (node.right == null) {
node.right = new RedBlackNode(key);
node.right.parent = node;
return node.right;
} else {
return this.insertNode(node.right, key);
}
}
fixTreeProperties(node) {
while (node && node.parent && node.parent.isRed()
&& node.color !== Colors.BLACK) {
let parent = node.parent;
const grandParent = parent.parent;
// 父节点是左侧子节点
if (grandParent && grandParent.left === parent) {
const uncle = grandParent.right;
// 叔叔节点也是红色——只需要重新填色
if (uncle && uncle.color === Colors.RED) {
grandParent.color = Colors.RED;
parent.color = Colors.BLACK;
uncle.color = Colors.BLACK;
node = grandParent;
} else {
// 节点是右侧子节点——左旋转
if (node === parent.right) {
this.rotationRR(parent);
node = parent;
parent = node.parent;
}
// 节点是左侧子节点——右旋转
this.rotationLL(grandParent);
parent.color = Colors.BLACK;
grandParent.color = Colors.RED;
node = parent;
}
} else {
// 父节点是右侧子节点
const uncle = grandParent.left;
// 叔叔节点是红色——只需要重新填色
if (uncle && uncle.color === Colors.RED) {
grandParent.color = Colors.RED;
parent.color = Colors.BLACK;
uncle.color = Colors.BLACK;
node = grandParent;
} else {
// 节点是左侧子节点——右旋转
if (node === parent.left) {
this.rotationLL(parent);
node = parent;
parent = node.parent;
}
// 节点是右侧子节点——左旋转
this.rotationRR(grandParent);
parent.color = Colors.BLACK;
grandParent.color = Colors.RED;
node = parent;
}
}
}
this.root.color = Colors.BLACK;
}
rotationLL(node) {
const tmp = node.left;
node.left = tmp.right;
if (tmp.right && tmp.right.key) {
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;
}
rotationRR(node) {
const tmp = node.right;
node.right = tmp.left;
if (tmp.left && tmp.left.key) {
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;
}
}