当前位置: 首页 > news >正文

c++实现跳表

原理

跳表(Skip List) 是一种随机化数据结构,用于高效查找、插入和删除,尤其适用于有序数据集合。相比链表,跳表通过多层索引结构加速查找,期望时间复杂度接近 O(log⁡n)。跳表的主要思想是:

  • 底层链表存储所有数据元素,保持有序。
  • 上层链表是稀疏索引,用于跳过部分节点,减少遍历的长度。

结构图

下面是一个跳表的结构示意:

Level 3:  [1] ----------------> [9]
Level 2:  [1] -----> [4] -----> [9]
Level 1:  [1] -----> [4] -----> [7] -----> [9]
Level 0:  [1] -> [2] -> [4] -> [5] -> [7] -> [8] -> [9]

如上图所示:

  1. 每一层都是一个有序链表。
  2. 每一层的节点是下一层的子集,存储重要的中间节点,形成分层索引
  3. 查找过程:从最高层开始,先向右移动,如果目标值超出范围,则向下移动到下一层。重复此过程直到找到目标节点。

优缺点

优点

  • 插入、删除和查找的期望时间复杂度为 O(log⁡n)。
  • 实现简单,比红黑树和AVL树更容易理解和维护。

缺点

  • 需要额外的空间存储索引层节点。

代码示例(c++)

下面是一段简单的 C++ 跳表实现,包括节点结构定义、插入、查找和显示功能。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;class Node {
public:int value;vector<Node*> forward;  // 每层的前向指针Node(int val, int level) : value(val), forward(level + 1, nullptr) {}
};class SkipList {
private:int maxLevel;  // 跳表的最大层数float probability;  // 晋升概率Node* header;  // 头节点int currentLevel;  // 当前跳表的层数public:SkipList(int maxLevel, float probability) : maxLevel(maxLevel), probability(probability), currentLevel(0) {header = new Node(-1, maxLevel);  // 头节点初始化为-1srand(time(nullptr));  // 初始化随机数种子}// 随机生成节点的层数int randomLevel() {int lvl = 0;while ((rand() / double(RAND_MAX)) < probability && lvl < maxLevel) {lvl++;}return lvl;}// 插入新节点void insert(int value) {vector<Node*> update(maxLevel + 1);Node* current = header;// 从最高层向下查找插入位置for (int i = currentLevel; 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) {int lvl = randomLevel();if (lvl > currentLevel) {for (int i = currentLevel + 1; i <= lvl; i++) {update[i] = header;}currentLevel = lvl;}Node* newNode = new Node(value, lvl);for (int i = 0; i <= lvl; i++) {newNode->forward[i] = update[i]->forward[i];update[i]->forward[i] = newNode;}cout << "Inserted value: " << value << " at level: " << lvl << endl;}}// 查找节点bool search(int value) {Node* current = header;for (int i = currentLevel; 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;}// 打印跳表结构void display() {for (int i = currentLevel; i >= 0; i--) {Node* current = header->forward[i];cout << "Level " << i << ": ";while (current) {cout << current->value << " ";current = current->forward[i];}cout << endl;}}
};int main() {SkipList skipList(4, 0.5);  // 最大层数为4,晋升概率为0.5skipList.insert(3);skipList.insert(6);skipList.insert(7);skipList.insert(9);skipList.insert(12);skipList.insert(19);cout << "Skip List Structure:" << endl;skipList.display();cout << "Search 7: " << (skipList.search(7) ? "Found" : "Not Found") << endl;cout << "Search 4: " << (skipList.search(4) ? "Found" : "Not Found") << endl;return 0;
}

代码解析

  1. Node 类
    • 表示跳表中的节点,包含节点的值和指向不同层节点的指针向量 forward
  2. SkipList 类
    • 实现了跳表的主要功能,包括插入、查找和显示结构。
    • randomLevel:用于随机生成节点的层数,控制索引的稀疏程度。
    • insert:插入元素到跳表中,如果新节点的层数超过当前最大层数,则更新索引。
    • search:查找目标值是否存在。
  3. 主函数
    • 初始化跳表并插入若干元素,测试插入和查找功能。

运行结果

Inserted value: 3 at level: 0
Inserted value: 6 at level: 1
Inserted value: 7 at level: 2
Inserted value: 9 at level: 0
Inserted value: 12 at level: 1
Inserted value: 19 at level: 3
Skip List Structure:
Level 3: 19 
Level 2: 7 19 
Level 1: 6 12 19 
Level 0: 3 6 7 9 12 19 
Search 7: Found
Search 4: Not Found

总结

  • 时间复杂度:查找、插入、删除的期望时间复杂度为 O(log⁡n)O(\log n)O(logn)。
  • 空间复杂度:O(nlog⁡n)O(n \log n)O(nlogn),因为每个节点可能会出现在多层中。

跳表的实现简单且高效,常用于 Redis 等数据库的有序集合。

http://www.lryc.cn/news/467915.html

相关文章:

  • 新探索研究生英语读写教程pdf答案(基础级)
  • 管道与共享内存
  • ES 自定义排序方式
  • 在vue中,编写一个li标签同时使用v-for和v-if,谁的优先级更高
  • Java 后端开发面试题及其答案
  • C++,STL 045(24.10.24)
  • 二叉树习题其五【力扣】【算法学习day.12】
  • 【数据库】Mysql的锁类型
  • 自媒体短视频制作素材下载网站推荐,让创作更简单
  • Altium Designer 入门基础教程(五)
  • Java题集练习3
  • 【部署篇】Haproxy-01安装部署(源码方式安装)
  • 开拓鸿蒙测试新境界,龙测科技引领自动化测试未来
  • Java项目-基于springboot框架的自习室预订系统项目实战(附源码+文档)
  • 调整数组奇偶数顺序
  • Electron调用nodejs的cpp .node扩展【非安全】
  • 一文了解AOSP是什么?
  • ffmpeg视频边缘模糊,打造梦幻般的视觉效果!
  • [Wireshark] 使用Wireshark抓包https数据包并显示为明文、配置SSLKEYLOGFILE变量(附下载链接)
  • 大话红黑树之(1)入门介绍
  • ESC/POS图片打印指令
  • Unity之如何在Linux上部署Dedicated Server专用服务器
  • 十、Linux 故障排除专业案例分享
  • 智慧楼宇平台,构筑未来智慧城市的基石
  • JVM 实战篇(一万字)
  • 线程同步之双摄
  • 使用 PyTorch 构建 LSTM 股票价格预测模型
  • 【C++篇】C++类与对象深度解析(五):友元机制、内部类与匿名对象的讲解
  • 模型训练进度条的代码
  • 直观理解反向传播 | Chapter 3 | Deep Learning | 3Blue1Brown