数据结构之树
1. 相关术语
- 第一个节点叫做根节点
- 包含至少一个子节点的节点叫做内部节点
- 树最后表示结束不包含任何数据的用null表示的节点叫做叶节点
2. 二叉搜索树
左侧的子节点小于父节点,右侧的子节点大于父节点。
- insert(key) 插入一个元素
- search(key) 查找树中是否包含key元素,是返回true, 否返回false
- inOrderTraverse() 中序遍历,以从小到大的顺序遍历所有节点。
- preOrderTraverse() 先序遍历,先遍历父节点,在遍历子节点。打印一个结构化的文档。
- postOrderTraverse() 后序遍历,先遍历子节点在遍历父节点。计算一个目录以及其子目录中所有文件占用的空间大小。
- min() 查找最小值
- max() 查找最大值
- remove(key) 移除某个元素
2.1 节点对象
class Node {
constructor(key) {
this.key = key;
this.left = null;
this.right = null
}
}
2.2 比较函数
const COMPARE = {
LESS_THAN: 'LESS_THAN',
EQUALITY: 'EQUALITY',
BIGGER_THAN: 'BIGGER_THAN'
}
// 2. 比较函数
function defaultCompareFn(a, b) {
if (a < b) {
return COMPARE.BIGGER_THAN;
}
else if (a > b) {
return COMPARE.LESS_THAN;
}
else {
return COMPARE.EQUALITY;
}
}
2.3 树对象
class BinarySearchTree {
constructor(compareFn = defaultCompareFn) {
this.root = null;
this.compareFn = compareFn;
}
insert(key) {
if (this.root === null) {
this.root = new Node(key);
}
else {
this.insertNode(this.root, key);
}
}
insertNode(node, key) {
if (this.compareFn(node.key, 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);
}
}
}
// 查找特定节点
search(key) {
return this.searchNode(this.root, key);
}
searchNode(node, key) {
if (node === null) return false;
const compareResult = this.compareFn(node.key, key);
if (compareResult === COMPARE.LESS_THAN) {
return this.searchNode(node.left, key);
}
else if (compareResult === COMPARE.BIGGER_THAN) {
return this.searchNode(node.right, key);
}
else {
return true;
}
}
// 查找最小值
min() {
return this.minNode(this.root);
}
minNode(node) {
let currentNode = node;
while (currentNode !== null && currentNode.left !== null) {
currentNode = currentNode.left;
}
return currentNode;
}
// 查找最大值
max() {
return this.maxNode(this.root);
}
maxNode(node) {
let currentNode = node;
while (currentNode !== null && currentNode.right !== null) {
currentNode = currentNode.right;
}
return currentNode;
}
// 中序遍历
inOrderTraverse(callback) {
this.inOrderTraverseNode(this.root, callback);
}
inOrderTraverseNode(node, callback) {
if (node !== null) {
this.inOrderTraverseNode(node.left, callback);
callback(node);
this.inOrderTraverseNode(node.right, callback);
}
}
preOrderTraverse(callback) {
this.preOrderTraverseNode(this.root, callback);
}
preOrderTraverseNode(node, callback) {
if (node !== null) {
callback(node);
this.preOrderTraverseNode(node.left, callback);
this.preOrderTraverseNode(node.right, callback);
}
}
// 后序遍历
postOrderTraverse(callback) {
this.postOrderTraverseNode(this.root, callback);
}
postOrderTraverseNode(node, callback) {
if (node !== null) {
this.preOrderTraverseNode(node.left, callback);
this.preOrderTraverseNode(node.right, callback);
callback(node);
}
}
remove(key) {
this.root = this.removeNode(this.root, key);
}
removeNode(node, key) {
if (node === null) return null;
const compareResult = this.compareFn(node.key, key);
if (compareResult === COMPARE.LESS_THAN) {
node.left = this.removeNode(node.left, key);
return node;
}
else if (compareResult === COMPARE.BIGGER_THAN) {
node.right = this.removeNode(node.right, key);
return node;
}
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;
}
let aux = this.minNode(node.right);
node.key = aux.key;
node.right = this.removeNode(node.right, aux.key);
return node;
}
}
let bst = new BinarySearchTree()
bst.insert(10);
bst.insert(1);
bst.insert(2);
bst.insert(5);
bst.insert(9);
console.log('bst:', bst.root);
console.log('min', bst.min().key);
console.log('max', bst.max().key);
bst.inOrderTraverse(function(node) {
console.log('key:', node.key);
})
3. AVL树
任何一个节点,他的左子树和右子树高度最多相差1。
本质上还是一种二叉搜索树,可以继承BinarySearchTree类,只需要重新插入和删除等可能会影响平衡的方法即可。
class AVLTree extends BinarySearchTree {
constructor(compareFn = defaultCompareFn) {
super(compareFn);
this.root = null
this.compareFn = compareFn;
}
}
3.1 节点高度
从节点到最小子节点的距离。
getNodeHeight(node) {
if (node === null) return -1;
return Math.max(
this.getNodeHeight(node.left),
this.getNodeHeight(node.right)
) + 1;
}
3.2 平衡因子
根据节点高度获取节点的平衡因子,如果平衡因子为 -1、0、+1,表示该节点处于平衡状态,不需要做平衡处理,否则,表示该节点失衡,需要做平衡处理。
平衡因子常量:
const BALANCE_FACTOR = {
UNBALANCE_RIGHT: -2,
SLIGHTLY_UNBALANCE_RIGHT: -1,
BALANCE: 0,
SLIGHTLY_UNBALANCE_LEFT: 1,
UNBALANCE_LEFT: 2
}
getBalanceFactor(node) {
const heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right);
switch (heightDifference) {
case -2:
return BALANCE_FACTOR.UNBALANCE_RIGHT;
case -1:
return BALANCE_FACTOR.SLIGHTLY_UNBALANCE_RIGHT;
case 1:
return BALANCE_FACTOR.SLIGHTLY_UNBALANCE_LEFT;
case 2:
return BALANCE_FACTOR.UNBALANCE_LEFT;
default:
return BALANCE_FACTOR.BALANCE;
}
}
3.3 平衡方法
3.3.1 LL型
左侧子树高度大于右侧子树高度超过1,节点Node向右旋转,变成左侧子节点的右侧节点,左侧子节点的右侧节点,变成节点Node的左侧节点。
rotateLL(node) {
let temp = node.left;
node.left = temp.right;
temp.right = node;
return temp;
}
3.3.2 RR型
右侧子树的高度比左侧子树的高度大于1,节点Node向左旋转,变成右侧节点的左侧节点,右侧节点的左侧节点变成节点Node的右侧节点。
rotateRR(node) {
let temp = node.right;
node.right = temp.left;
temp.left = node;
return temp;
}
3.3.3 LR型
左侧子树的高度比右侧子树的高度大于1,并且左侧子节点的右侧子树高度大于左侧子节点的左侧子树高度。节点Node的左侧子节点向左旋转,变成LL型,节点Node再向右旋转。
rotateLR(node) {
node.left = this.rotateRR(node.left);
return this.rotateLL(node);
}
3.3.4 RL型
右侧子树高度比左侧子树高度大于1,并且右侧子节点的左侧子树高度比右侧子树高度大。节点Node的右侧子节点向右旋转,变成RR型,节点Node在向左旋转。
rotateRL(node) {
node.right = this.rotateLL(node.right);
return this.rotateRR(node);
}
3.4 插入元素
insert(key) {
this.root = this.insertNode(this.root, key);
}
insertNode(node, key) {
if (node === null) {
return new Node(key);
}
if (this.compareFn(node.key, key) === COMPARE.LESS_THAN) {
node.left = this.insertNode(node.left, key);
}
else if (this.compareFn(node.key, key) === COMPARE.BIGGER_THAN) {
node.right = this.insertNode(node.right, key);
}
else {
return node;
}
// 处理平衡问题
const factor = this.getBalanceFactor(node);
// 选择旋转类型
if (factor === BALANCE_FACTOR.UNBALANCE_LEFT) {
if (this.compareFn(node.left.key, key) === COMPARE.LESS_THAN) {
node = this.rotateLL(node);
}
else {
node = this.rotateLR(node);
}
}
else if (factor === BALANCE_FACTOR.UNBALANCE_RIGHT) {
if (this.compareFn(node.right.key, key) === COMPARE.BIGGER_THAN) {
node = this.rotateRR(node);
}
else {
node = this.rotateRL(node);
}
}
return node;
}
3.5 删除元素
removeNode(node, key) {
node = super.removeNode(node, key);
if (node === null) return node;
// 处理平衡问题
const factor = this.getBalanceFactor(node);
if (factor === BALANCE_FACTOR.UNBALANCE_LEFT) {
const factorLeft = this.getBalanceFactor(node.left);
// LL型
if (
factorLeft === BALANCE_FACTOR.BALANCE ||
factorLeft === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_LEFT
) {
return this.rotateLL(node);
}
// LR型
else if (factorLeft === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_RIGHT) {
return this.rotateLR(node);
}
}
else if (factor === BALANCE_FACTOR.UNBALANCE_RIGHT) {
const factorRight = this.getBalanceFactor(node.right);
// RR型
if (
factorRight === BALANCE_FACTOR.BALANCE ||
factorRight === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_RIGHT
) {
return this.rotateRR(node);
}
// RL型
else if (factorRight === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_LEFT) {
return this.rotateRL(node);
}
}
return node;
}