如何用js实现红黑树
红黑树是一种自平衡的二叉查找树,它的实现需要注意许多细节。以下是一些实现红黑树的基本步骤,使用 JavaScript 语言实现:
- 创建节点类:定义一个节点类,包含节点值、左右子节点、颜色属性等。
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
this.color = 'red';
}
}
- 创建红黑树类:定义一个红黑树类,包含根节点、插入、删除、旋转等方法。
class RedBlackTree {
constructor() {
this.root = null;
}
// 插入节点
insert(value) {}
// 删除节点
delete(value) {}
// 左旋
rotateLeft(node) {}
// 右旋
rotateRight(node) {}
// 颜色翻转
flipColors(node) {}
}
- 实现插入操作:按照二叉查找树的规则插入节点,然后根据红黑树的特性进行修正。具体来说,如果插入的节点的父节点是红色,那么需要进行颜色翻转、左旋、右旋等操作,使得树重新满足红黑树的特性。
insert(value) {
const node = new Node(value);
if (!this.root) {
// 插入根节点
node.color = 'black';
this.root = node;
return;
}
let current = this.root;
while (current) {
if (value < current.value) {
if (!current.left) {
// 插入左子节点
current.left = node;
break;
}
current = current.left;
} else {
if (!current.right) {
// 插入右子节点
current.right = node;
break;
}
current = current.right;
}
}
// 修正红黑树
if (current.color === 'red' && current.parent.color === 'red') {
let uncle = null;
if (current.parent === current.parent.parent.left) {
uncle = current.parent.parent.right;
if (uncle && uncle.color === 'red') {
// case 1: 父节点和叔节点都是红色
current.parent.color = 'black';
uncle.color = 'black';
current.parent.parent.color = 'red';
this.insert(current.parent.parent.value);
} else {
if (current === current.parent.right) {
// case 2: 父节点是红色,叔节点是黑色,当前节点是右子节点
current = current.parent;
this.rotateLeft(current);
}
// case 3: 父节点是红色,叔节点是黑色,当前节点是左子节点
current.parent.color = 'black';
current.parent.parent.color = 'red';
this.rotateRight(current.parent.parent);
}
} else {
uncle = current.parent.parent.left;
if (uncle && uncle.color === 'red') {
// case 1: 父节点和叔节点都是红色
current.parent.color = 'black';
uncle.color = 'black';
current.parent.parent.color = 'red';
this.insert(current.parent.parent.value);
} else {
if (current === current.parent.left) {
// case 2: 父节点是红色,叔节点是黑色,当前节点是左子节点
current = current.parent;
this.rotateRight(current);
}
// case 3: 父节点是红色,叔节点是黑色,当前节点是右子节点
current.parent.color = 'black';
current.parent.parent.color = 'red';
this.rotateLeft(current.parent.parent);
}
}
}
this.root.color = 'black';
}
- 实现删除操作:删除操作需要考虑多种情况,包括要删除的节点有 0、1、2 个子节点等不同情况,具体实现时需要分别考虑。删除节点后,同样需要进行红黑树的修正。
delete(value) {
let current = this.root;
while (current) {
if (value === current.value) {
// 找到要删除的节点
if (!current.left && !current.right) {
// case 1: 要删除的节点没有子节点
if (current.color === 'red') {
// 直接删除即可
if (current === current.parent.left) {
current.parent.left = null;
} else {
current.parent.right = null;
}
} else {
// 要删除的节点是黑色的情况比较复杂,需要进行修正
this.deleteCase1(current);
}
} else if (current.left && current.right) {
// case 2: 要删除的节点有两个子节点
let successor = current.right;
while (successor.left) {
successor = successor.left;
}
current.value = successor.value;
// 转换为删除后继节点的情况
current = successor;
this.deleteCase1(current);
} else {
// case 3: 要删除的节点只有一个子节点
const child = current.left || current.right;
if (current.color === 'red') {
// 直接用子节点替换即可
if (current === current.parent.left) {
current.parent.left = child;
} else {
current.parent.right = child;
}
child.parent = current.parent;
} else {
// 要删除的节点是黑色的情况比较复杂,需要进行修正
if (child.color === 'red') {
// case 3.1: 要删除的节点是黑色,但是子节点是红色
child.color = 'black';
if (current === current.parent.left) {
current.parent.left = child;
} else {
current.parent.right = child;
}
child.parent = current.parent;
} else {
// case 3.2: 要删除的节点是黑色,子节点是黑色
this.deleteCase1(child);
if (current === current.parent.left) {
current.parent.left = child;
} else {
current.parent.right = child;
}
child.parent = current.parent;
}
}
}
break;
} else if (value < current.value) {
current = current.left;
} else {
current = current.right;
}
}
}
// 删除节点时,要考虑要删除的节点是黑色的情况
deleteCase1(node) {
if (node === this.root) {
// case 1: 要删除的节点是根节点
this.root = null;
} else if (node.parent.left === node) {
// case 2: 要删除的节点是左子节点
this.deleteCase2(node, node.parent.right);
} else {
// case 3: 要删除的节点是右子节点
this.deleteCase2(node, node.parent.left);
}
}
deleteCase2(node, sibling) {
if (sibling.color === 'red') {
// case 2.1: 兄弟节点是红色
sibling.color = 'black';
node.parent.color = 'red';
if (node === node.parent.left) {
this.rotateLeft(node.parent);
sibling = node.parent.right;
} else {
this.rotateRight(node.parent);
sibling = node.parent.left;
}
}
this.deleteCase3(node, sibling);
}
deleteCase3(node, sibling) {
if (node.parent.color === 'black' && sibling.color === 'black' && (!sibling.left || sibling.left.color === 'black') && (!sibling.right || sibling.right.color === 'black')) {
// case 2.2: 兄弟节点是黑色,且兄弟节点的子节点都是黑色
sibling.color = 'red';
this.deleteCase1(node.parent);
} else {
this.deleteCase4(node, sibling);
}
}
deleteCase4(node, sibling) {
if (node.parent.color === 'red' && sibling.color === 'black' && (!sibling.left || sibling.left.color === 'black') && (!sibling.right || sibling.right.color === 'black')) {
// case 2.3: 父节点是红色,兄弟节点是黑色,且兄弟节点的子节点都是黑色
sibling.color = 'red';
node.parent.color = 'black';
} else {
this.deleteCase5(node, sibling);
}
}
deleteCase5(node, sibling) {
if (sibling.color === 'black') {
if (node === node.parent.left && sibling.right && sibling.right.color === 'red' && (!sibling.left || sibling.left.color === 'black')) {
// case 2.4: 要删除的节点是左子节点,兄弟节点是黑色,兄弟节点的右子节点是红色,左子节点是黑色
sibling.color = 'red';
sibling.right.color = 'black';
this.rotateLeft(sibling);
sibling = node.parent.right;
} else if (node === node.parent.right && sibling.left && sibling.left.color === 'red' && (!sibling.right || sibling.right.color === 'black')) {
// case 2.4: 要删除的节点是右子节点,兄弟节点是黑色,兄弟节点的左子节点是红色,右子节点是黑色
sibling.color = 'red';
sibling.left.color = 'black';
this.rotateRight(sibling);
sibling = node.parent.left;
}
}
this.deleteCase6(node, sibling);
}
deleteCase6(node, sibling) {
sibling.color = node.parent.color;
node.parent.color = 'black';
if (node === node.parent.left) {
sibling.right.color = 'black';
this.rotateLeft(node.parent);
} else {
sibling.left.color = 'black';
this.rotateRight(node.parent);
}
}
- 实现旋转操作:旋转操作包括左旋和右旋两种,它们是红黑树实现的核心操作。通过旋转操作,可以将树的结构进行调整,使得树重新满足红黑树的特性。
rotateLeft(node) {
const parent = node.parent;
const right = node.right;
const left = right.left;
if (parent) {
if (node === parent.left) {
parent.left = right;
} else {
parent.right = right;
}
} else {
this.root = right;
}
right.parent = parent;
node.parent = right;
right.left = node;
node.right = left;
if (left) {
left.parent = node;
}
}
rotateRight(node) {
const parent = node.parent;
const left = node.left;
const right = left.right;
if (parent) {
if (node === parent.left) {
parent.left = left;
} else {
parent.right = left;
}
} else {
this.root = left;
}
left.parent = parent;
node.parent = left;
left.right = node;
node.left = right;
if (right) {
right.parent = node;
}
}
- 实现颜色翻转操作:颜色翻转操作用于将红黑树中的红节点和黑节点进行颜色交换,以保证树的平衡性。
flipColors(node) {
node.color = 'red';
node.left.color = 'black';
node.right.color = 'black';
if (node === this.root) {
node.color = 'black';
} else if (node.parent.color === 'red') {
this.flipColors(node.parent);
}
}
这些是实现红黑树的基本步骤,实际上还需要考虑一些细节,例如节点的父节点、子节点、兄弟节点等的指针关系,以及树的遍历、搜索、输出等操作。总之,红黑树是一种比较复杂的数据结构,需要仔细理解和实现。
原文地址: https://www.cveoy.top/t/topic/32B 著作权归作者所有。请勿转载和采集!