当前位置:首页 > JavaScript

JS实现跳表

2026-02-28 19:17:59JavaScript

跳表(Skip List)简介

跳表是一种基于概率的平衡数据结构,通过多层链表实现高效查找、插入和删除操作,时间复杂度为 $O(\log n)$。其核心思想是通过“跳跃”式访问节点减少遍历次数。

跳表节点结构

跳表节点包含值(value)和指向后续节点的指针数组(forward)。每一层对应一个指针,用于在不同层级间跳跃。

JS实现跳表

class SkipListNode {
  constructor(value, level) {
    this.value = value;
    this.forward = new Array(level).fill(null); // 初始化各层指针为null
  }
}

跳表类实现

跳表类需初始化头节点、最大层级和概率因子(通常为0.5)。

JS实现跳表

class SkipList {
  constructor() {
    this.maxLevel = 16; // 最大层数
    this.head = new SkipListNode(null, this.maxLevel); // 头节点
    this.level = 1; // 当前有效层数
    this.p = 0.5; // 概率因子
  }

  // 随机生成节点层数
  randomLevel() {
    let level = 1;
    while (Math.random() < this.p && level < this.maxLevel) {
      level++;
    }
    return level;
  }
}

查找操作

从最高层开始查找,逐步向下直至找到目标或确认不存在。

search(value) {
  let current = this.head;
  for (let i = this.level - 1; i >= 0; i--) {
    while (current.forward[i] && current.forward[i].value < value) {
      current = current.forward[i];
    }
  }
  current = current.forward[0];
  return current && current.value === value ? current : null;
}

插入操作

  1. 确定插入位置并记录每层的前驱节点。
  2. 随机生成新节点层数,更新前驱节点的指针。
insert(value) {
  const update = new Array(this.maxLevel).fill(null);
  let current = this.head;

  for (let i = this.level - 1; i >= 0; i--) {
    while (current.forward[i] && current.forward[i].value < value) {
      current = current.forward[i];
    }
    update[i] = current;
  }

  const level = this.randomLevel();
  if (level > this.level) {
    for (let i = this.level; i < level; i++) {
      update[i] = this.head;
    }
    this.level = level;
  }

  const newNode = new SkipListNode(value, level);
  for (let i = 0; i < level; i++) {
    newNode.forward[i] = update[i].forward[i];
    update[i].forward[i] = newNode;
  }
}

删除操作

类似插入,需先定位节点并更新前驱指针。

delete(value) {
  const update = new Array(this.maxLevel).fill(null);
  let current = this.head;

  for (let i = this.level - 1; 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 > 1 && !this.head.forward[this.level - 1]) {
    this.level--;
  }
  return true;
}

复杂度分析

  • 空间复杂度: $O(n \log n)$(最坏情况),实际接近 $O(n)$。
  • 时间复杂度: 查找、插入、删除均为 $O(\log n)$。

应用场景

  • Redis的有序集合(ZSET)底层实现。
  • 替代平衡树(如AVL、红黑树)的简化方案。

标签: JS
分享给朋友:

相关文章

JS如何访问react内部的数据

JS如何访问react内部的数据

访问 React 组件内部数据的方法 在 React 中,组件内部的数据通常通过 state 或 props 管理。以下是几种常见的访问方式: 通过 state 访问数据 React 组件的内部状态…

JS实现文本的删除

JS实现文本的删除

使用 substring() 方法 通过指定起始和结束索引截取字符串的一部分,间接实现删除效果。 let str = "Hello World"; let newStr = str.substr…

JS实现ln

JS实现ln

在JavaScript中实现自然对数(ln)功能可以通过以下几种方式完成: 使用Math对象的原生方法 JavaScript内置的Math对象提供了Math.log()方法,该方法默认计算以自然对数…

实现阶乘JS

实现阶乘JS

递归实现阶乘 递归是一种直接按照数学定义实现阶乘的方法。n的阶乘可以表示为n乘以(n-1)的阶乘,基础情况是0的阶乘为1。 function factorialRecursive(n) { if…

JS实现inpubox

JS实现inpubox

实现 InputBox 的基本结构 使用 HTML 和 CSS 创建一个基础的输入框结构,确保样式简洁且易于扩展。 <div class="input-box"> <input…

JS原子锁实现

JS原子锁实现

实现原子锁的方法 使用JavaScript的Atomics对象和SharedArrayBuffer可以实现原子锁。Atomics提供了一组静态方法用于对SharedArrayBuffer进行原子操作,…