算法2026-05-07·12 分钟
算法知识库:高级数据结构实现
高级数据结构如跳表、B树、Trie树、后缀树的 JavaScript/TypeScript 实现。
高级数据结构实现
1. 跳表 (Skip List)
时间复杂度: 平均 O(log n) (查找、插入、删除) 空间复杂度: O(n log n)
ts
class SkipListNode<T> {
value: T;
forward: SkipListNode<T>[];
constructor(value: T, level: number) {
this.value = value;
this.forward = new Array(level + 1).fill(null);
}
}
class SkipList<T> {
private head: SkipListNode<T>;
private maxLevel: number;
private level: number;
private p: number; // 概率因子
constructor(maxLevel: number = 16, p: number = 0.5) {
this.maxLevel = maxLevel;
this.level = 0;
this.p = p;
this.head = new SkipListNode<T>(null as any, maxLevel);
}
private randomLevel(): number {
let level = 0;
while (Math.random() < this.p && level < this.maxLevel) {
level++;
}
return level;
}
insert(value: T): void {
const update: SkipListNode<T>[] = new Array(this.maxLevel + 1).fill(this.head);
let current = this.head;
// 找到插入位置
for (let i = this.level; i >= 0; i--) {
while (current.forward[i] && current.forward[i].value < value) {
current = current.forward[i];
}
update[i] = current;
}
const newLevel = this.randomLevel();
if (newLevel > this.level) {
for (let i = this.level + 1; i <= newLevel; i++) {
update[i] = this.head;
}
this.level = newLevel;
}
const newNode = new SkipListNode<T>(value, newLevel);
// 更新指针
for (let i = 0; i <= newLevel; i++) {
newNode.forward[i] = update[i].forward[i];
update[i].forward[i] = newNode;
}
}
search(value: T): boolean {
let current = this.head;
for (let i = this.level; i >= 0; i--) {
while (current.forward[i] && current.forward[i].value < value) {
current = current.forward[i];
}
}
current = current.forward[0];
return current !== null && current.value === value;
}
delete(value: T): boolean {
const update: SkipListNode<T>[] = new Array(this.maxLevel + 1).fill(this.head);
let current = this.head;
// 找到删除位置
for (let i = this.level; i >= 0; i--) {
while (current.forward[i] && current.forward[i].value < value) {
current = current.forward[i];
}
update[i] = current;
}
current = current.forward[0];
if (!current || current.value !== value) {
return false;
}
// 更新指针
for (let i = 0; i <= this.level; i++) {
if (update[i].forward[i] !== current) {
break;
}
update[i].forward[i] = current.forward[i];
}
// 降低层级
while (this.level > 0 && this.head.forward[this.level] === null) {
this.level--;
}
return true;
}
print(): void {
for (let i = 0; i <= this.level; i++) {
let current = this.head.forward[i];
const levelStr = `Level ${i}: `;
let str = levelStr;
while (current) {
str += `${current.value} -> `;
current = current.forward[i];
}
str += 'null';
console.log(str);
}
}
}2. B树 (B-Tree)
ts
class BTreeNode<T> {
keys: T[];
children: BTreeNode<T>[];
isLeaf: boolean;
t: number; // 最小度数
constructor(t: number, isLeaf: boolean = true) {
this.t = t;
this.isLeaf = isLeaf;
this.keys = [];
this.children = [];
}
}
class BTree<T> {
private root: BTreeNode<T> | null;
private t: number; // 最小度数
constructor(t: number) {
this.root = null;
this.t = t;
}
search(key: T): boolean {
return this.searchNode(this.root, key);
}
private searchNode(node: BTreeNode<T> | null, key: T): boolean {
if (!node) return false;
let i = 0;
while (i < node.keys.length && key > node.keys[i]) {
i++;
}
if (i < node.keys.length && key === node.keys[i]) {
return true;
}
if (node.isLeaf) {
return false;
}
return this.searchNode(node.children[i], key);
}
insert(key: T): void {
if (!this.root) {
this.root = new BTreeNode<T>(this.t, true);
this.root.keys.push(key);
return;
}
if (this.root.keys.length === 2 * this.t - 1) {
const newRoot = new BTreeNode<T>(this.t, false);
newRoot.children.push(this.root);
this.splitChild(newRoot, 0);
this.root = newRoot;
}
this.insertNonFull(this.root, key);
}
private insertNonFull(node: BTreeNode<T>, key: T): void {
let i = node.keys.length - 1;
if (node.isLeaf) {
// 找到插入位置
while (i >= 0 && key < node.keys[i]) {
i--;
}
node.keys.splice(i + 1, 0, key);
} else {
// 找到子节点
while (i >= 0 && key < node.keys[i]) {
i--;
}
i++;
if (node.children[i].keys.length === 2 * this.t - 1) {
this.splitChild(node, i);
if (key > node.keys[i]) {
i++;
}
}
this.insertNonFull(node.children[i], key);
}
}
private splitChild(parent: BTreeNode<T>, i: number): void {
const child = parent.children[i];
const newChild = new BTreeNode<T>(this.t, child.isLeaf);
// 提升中间键到父节点
const midKey = child.keys[this.t - 1];
parent.keys.splice(i, 0, midKey);
parent.children.splice(i + 1, 0, newChild);
// 移动右半部分到新节点
newChild.keys = child.keys.splice(this.t);
if (!child.isLeaf) {
newChild.children = child.children.splice(this.t);
}
}
delete(key: T): boolean {
if (!this.root) return false;
const result = this.deleteFromNode(this.root, key);
// 如果根节点为空,降低树高
if (this.root.keys.length === 0 && !this.root.isLeaf) {
this.root = this.root.children[0];
}
return result;
}
private deleteFromNode(node: BTreeNode<T>, key: T): boolean {
let i = 0;
while (i < node.keys.length && key > node.keys[i]) {
i++;
}
if (i < node.keys.length && key === node.keys[i]) {
if (node.isLeaf) {
// 从叶节点删除
node.keys.splice(i, 1);
return true;
} else {
// 从内部节点删除
return this.deleteFromInternalNode(node, i);
}
} else {
if (node.isLeaf) {
return false;
}
const flag = i === node.keys.length;
// 确保子节点至少有 t 个键
if (node.children[i].keys.length < this.t) {
this.fill(node, i);
}
if (flag && i > node.keys.length) {
return this.deleteFromNode(node.children[i - 1], key);
} else {
return this.deleteFromNode(node.children[i], key);
}
}
}
private deleteFromInternalNode(node: BTreeNode<T>, i: number): boolean {
const key = node.keys[i];
if (node.children[i].keys.length >= this.t) {
// 前驱替换
const pred = this.getPredecessor(node.children[i]);
node.keys[i] = pred;
return this.deleteFromNode(node.children[i], pred);
} else if (node.children[i + 1].keys.length >= this.t) {
// 后继替换
const succ = this.getSuccessor(node.children[i + 1]);
node.keys[i] = succ;
return this.deleteFromNode(node.children[i + 1], succ);
} else {
// 合并子节点
this.merge(node, i);
return this.deleteFromNode(node.children[i], key);
}
}
private getPredecessor(node: BTreeNode<T>): T {
let current = node;
while (!current.isLeaf) {
current = current.children[current.children.length - 1];
}
return current.keys[current.keys.length - 1];
}
private getSuccessor(node: BTreeNode<T>): T {
let current = node;
while (!current.isLeaf) {
current = current.children[0];
}
return current.keys[0];
}
private fill(node: BTreeNode<T>, i: number): void {
if (i !== 0 && node.children[i - 1].keys.length >= this.t) {
this.borrowFromPrev(node, i);
} else if (i !== node.keys.length && node.children[i + 1].keys.length >= this.t) {
this.borrowFromNext(node, i);
} else {
if (i !== node.keys.length) {
this.merge(node, i);
} else {
this.merge(node, i - 1);
}
}
}
private borrowFromPrev(node: BTreeNode<T>, i: number): void {
const child = node.children[i];
const sibling = node.children[i - 1];
// 移动父节点的键到子节点开头
child.keys.unshift(node.keys[i - 1]);
// 移动兄弟节点的最后一个键到父节点
node.keys[i - 1] = sibling.keys.pop()!;
// 移动兄弟节点的子节点
if (!child.isLeaf) {
child.children.unshift(sibling.children.pop()!);
}
}
private borrowFromNext(node: BTreeNode<T>, i: number): void {
const child = node.children[i];
const sibling = node.children[i + 1];
// 移动父节点的键到子节点末尾
child.keys.push(node.keys[i]);
// 移动兄弟节点的第一个键到父节点
node.keys[i] = sibling.keys.shift()!;
// 移动兄弟节点的子节点
if (!child.isLeaf) {
child.children.push(sibling.children.shift()!);
}
}
private merge(node: BTreeNode<T>, i: number): void {
const child = node.children[i];
const sibling = node.children[i + 1];
// 移动父节点的键到子节点
child.keys.push(node.keys.splice(i, 1)[0]);
// 移动兄弟节点的所有键和子节点
child.keys.push(...sibling.keys);
if (!child.isLeaf) {
child.children.push(...sibling.children);
}
// 移除兄弟节点
node.children.splice(i + 1, 1);
}
}3. Trie 树 (前缀树)
ts
class TrieNode {
children: Map<string, TrieNode> = new Map();
isEndOfWord: boolean = false;
count: number = 0; // 记录经过此节点的单词数量
}
class Trie {
private root: TrieNode = new TrieNode();
insert(word: string): void {
let node = this.root;
for (const char of word) {
if (!node.children.has(char)) {
node.children.set(char, new TrieNode());
}
node = node.children.get(char)!;
node.count++;
}
node.isEndOfWord = true;
}
search(word: string): boolean {
const node = this.getNode(word);
return node !== null && node.isEndOfWord;
}
startsWith(prefix: string): boolean {
return this.getNode(prefix) !== null;
}
getNode(word: string): TrieNode | null {
let node = this.root;
for (const char of word) {
if (!node.children.has(char)) {
return null;
}
node = node.children.get(char)!;
}
return node;
}
// 获取以指定前缀开头的单词数量
countWordsStartingWith(prefix: string): number {
const node = this.getNode(prefix);
return node ? node.count : 0;
}
// 删除单词
delete(word: string): boolean {
let node = this.root;
const nodes: TrieNode[] = [node];
for (const char of word) {
if (!node.children.has(char)) {
return false;
}
node = node.children.get(char)!;
nodes.push(node);
}
if (!node.isEndOfWord) {
return false;
}
node.isEndOfWord = false;
// 从后往前清理不需要的节点
for (let i = nodes.length - 1; i >= 0; i--) {
const currentNode = nodes[i];
currentNode.count--;
if (currentNode.count === 0 && !currentNode.isEndOfWord) {
const parent = nodes[i - 1];
if (parent) {
const char = word[i - 1];
parent.children.delete(char);
}
}
}
return true;
}
// 获取所有单词
getAllWords(): string[] {
const result: string[] = [];
this.collectWords(this.root, '', result);
return result;
}
private collectWords(node: TrieNode, prefix: string, result: string[]): void {
if (node.isEndOfWord) {
result.push(prefix);
}
for (const [char, childNode] of node.children) {
this.collectWords(childNode, prefix + char, result);
}
}
// 获取以指定前缀开头的单词
getWordsWithPrefix(prefix: string): string[] {
const node = this.getNode(prefix);
if (!node) return [];
const result: string[] = [];
this.collectWords(node, prefix, result);
return result;
}
}4. 后缀树 (Suffix Tree)
ts
class SuffixTreeNode {
children: Map<string, SuffixTreeNode> = new Map();
start: number;
end: number;
suffixIndex: number = -1;
constructor(start: number = -1, end: number = -1) {
this.start = start;
this.end = end;
}
get length(): number {
return this.end - this.start + 1;
}
getEdgeString(text: string): string {
return text.substring(this.start, this.end + 1);
}
}
class SuffixTree {
private root: SuffixTreeNode = new SuffixTreeNode();
private text: string;
private remainingSuffixCount: number = 0;
private leafEnd: number = -1;
private rootEnd: number | null = null;
private splitEnd: number | null = null;
private size: number = -1;
constructor(text: string) {
this.text = text + '$'; // 添加终止符
this.size = this.text.length;
this.buildSuffixTree();
}
private buildSuffixTree(): void {
this.rootEnd = null;
this.splitEnd = null;
for (let i = 0; i < this.size; i++) {
this.remainingSuffixCount++;
this.leafEnd = i;
this.extendSuffixTree(i);
}
}
private extendSuffixTree(pos: number): void {
let needParent: SuffixTreeNode | null = null;
let needParentChar: string = '';
while (this.remainingSuffixCount > 0) {
if (this.activeLength === 0) {
this.activeEdge = pos;
}
if (!this.activeNode.children.has(this.text[this.activeEdge])) {
// 创建新叶子节点
const leaf = new SuffixTreeNode(pos, this.leafEnd);
this.activeNode.children.set(this.text[this.activeEdge], leaf);
if (needParent) {
needParent.children.set(needParentChar, this.activeNode);
needParent = null;
}
} else {
const next = this.activeNode.children.get(this.text[this.activeEdge])!;
if (this.walkDown(next)) {
continue;
}
if (this.text[next.start + this.activeLength] === this.text[pos]) {
if (needParent && this.activeNode !== this.root) {
needParent.children.set(needParentChar, this.activeNode);
needParent = null;
}
this.activeLength++;
break;
}
// 分裂节点
const split = new SuffixTreeNode(next.start, next.start + this.activeLength - 1);
this.activeNode.children.set(this.text[this.activeEdge], split);
const leaf = new SuffixTreeNode(pos, this.leafEnd);
split.children.set(this.text[pos], leaf);
next.start += this.activeLength;
split.children.set(this.text[next.start], next);
if (needParent) {
needParent.children.set(needParentChar, split);
}
}
this.remainingSuffixCount--;
if (this.activeNode === this.root && this.activeLength > 0) {
this.activeLength--;
this.activeEdge = pos - this.remainingSuffixCount + 1;
} else if (this.activeNode !== this.root) {
this.activeNode = this.activeNode.suffixLink!;
}
}
}
private activeNode: SuffixTreeNode = this.root;
private activeEdge: number = -1;
private activeLength: number = 0;
private walkDown(curr: SuffixTreeNode): boolean {
if (this.activeLength >= curr.length) {
this.activeEdge += curr.length;
this.activeLength -= curr.length;
this.activeNode = curr;
return true;
}
return false;
}
// 搜索子串
search(pattern: string): boolean {
let node = this.root;
let i = 0;
while (i < pattern.length) {
if (!node.children.has(pattern[i])) {
return false;
}
node = node.children.get(pattern[i])!;
let j = node.start;
while (i < pattern.length && j <= node.end) {
if (pattern[i] !== this.text[j]) {
return false;
}
i++;
j++;
}
}
return true;
}
// 查找所有出现位置
findAllOccurrences(pattern: string): number[] {
const positions: number[] = [];
this.findOccurrences(this.root, pattern, 0, positions);
return positions;
}
private findOccurrences(node: SuffixTreeNode, pattern: string, currentPos: number, positions: number[]): void {
if (node.suffixIndex !== -1) {
positions.push(node.suffixIndex);
}
for (const child of node.children.values()) {
let i = 0;
let j = child.start;
while (i < pattern.length && j <= child.end) {
if (pattern[i] !== this.text[j]) {
break;
}
i++;
j++;
}
if (i === pattern.length) {
this.collectAllLeaves(child, positions);
} else if (i > 0) {
this.findOccurrences(child, pattern.substring(i), currentPos + i, positions);
}
}
}
private collectAllLeaves(node: SuffixTreeNode, positions: number[]): void {
if (node.suffixIndex !== -1) {
positions.push(node.suffixIndex);
}
for (const child of node.children.values()) {
this.collectAllLeaves(child, positions);
}
}
}5. 实现要点
- 跳表通过多层索引实现 O(log n) 的查找、插入和删除。
- B树是平衡多路搜索树,广泛用于数据库索引。
- Trie 树适合字符串前缀匹配和自动补全。
- 后缀树用于高效的子串搜索和重复检测。
算法数据结构JavaScript