C++ SkipList简单实现

C++ SkipList简单实现SkipList h pragmaonce include vector structSkipLi SkipListNode intdata intlevel intm data std vector SkipListNode m forward classSkipLis public Ski SkipListNode vector

SkipList.h:

#pragma once #include  
     struct SkipListNode { 
    SkipListNode(int data, int level); int m_data; std::vector<SkipListNode*> m_forward; }; class SkipList { 
    public: SkipList(); ~SkipList(); public: bool Find(int data); bool Insert(int data); bool Remove(int data); public: void Print(); private: void FirstInsert(int data); bool IsEmpty(); private: SkipListNode* m_pHead; int m_count; int m_level; }; 

SkipList.cpp

#include "SkipList.h" #include  
     #include  
     int GetRandLevel() { 
    int destLevel = 1; while (1 == rand() % 2) ++destLevel; return destLevel; } SkipListNode::SkipListNode(int data, int level) : m_data(data) , m_forward(level) { 
    } SkipList::SkipList() : m_pHead(nullptr) , m_count(0) , m_level(1) { 
    auto pHead = new SkipListNode(INT_MIN, m_level); m_pHead = pHead; } SkipList::~SkipList() { 
    auto* pNode = m_pHead; while (pNode != nullptr) { 
    auto pNextNode = pNode->m_forward[0]; delete pNode; pNode = pNextNode; } } bool SkipList::Find(int data) { 
    if (IsEmpty()) return false; auto pCurNode = m_pHead; for (int curLevel = m_level - 1; curLevel >= 0; --curLevel) { 
    // 判断是否已经走到该层最后一个元素 if (nullptr == pCurNode->m_forward[curLevel]) continue; while (pCurNode->m_forward[curLevel]->m_data < data) { 
    pCurNode = pCurNode->m_forward[curLevel]; // 判断是否已经走到该层最后一个元素 if (nullptr == pCurNode->m_forward[curLevel]) break; } } if (data == pCurNode->m_forward[0]->m_data) { 
    return true; } return false; } void SkipList::Print() { 
    auto* pCurNode = m_pHead; while (pCurNode != nullptr) { 
    std::cout << pCurNode->m_data << "(" << int(pCurNode->m_forward.size()) << ")" << " "; pCurNode = pCurNode->m_forward[0]; } std::cout << std::endl; } void SkipList::FirstInsert(int data) { 
    int destLevel = GetRandLevel(); if (destLevel > m_level) { 
    destLevel = ++m_level; // 更新最高层数, 只增加一层 m_pHead->m_forward.resize(m_level); } auto pNewNode = new SkipListNode(data, destLevel); for (int curLevel = m_level - 1; curLevel >= 0; --curLevel) { 
    m_pHead->m_forward[curLevel] = pNewNode; pNewNode->m_forward[curLevel] = nullptr; } ++m_count; return; } bool SkipList::IsEmpty() { 
    return 0 == m_count; } bool SkipList::Insert(int data) { 
    if (0 == m_count) // 首次插入 { 
    FirstInsert(data); return true; } auto pNode = m_pHead; // 需要更新下一跳指针的节点 std::vector<SkipListNode*> updates(m_level); for (int curLevel = m_level - 1; curLevel >= 0; --curLevel) { 
    if (nullptr == pNode->m_forward[curLevel]) { 
    updates[curLevel] = pNode; continue; } while (pNode->m_forward[curLevel]->m_data < data) { 
    pNode = pNode->m_forward[curLevel]; if (nullptr == pNode->m_forward[curLevel]) break; } updates[curLevel] = pNode; } if ((pNode->m_forward[0] != nullptr) && (data == pNode->m_forward[0]->m_data)) { 
    // 已有节点处理 return false; } int destLevel = GetRandLevel(); if (destLevel > m_level) { 
    destLevel = ++m_level; // 更新最高层数 updates.resize(m_level); updates[m_level - 1] = m_pHead; m_pHead->m_forward.resize(m_level); } // 待插入元素 auto* pNewNode = new SkipListNode(data, destLevel); // 从插入节点的最高层开始向下处理,对插入节点最高层之上的指针无影响 for (int curLevel = destLevel - 1; curLevel >= 0; --curLevel) { 
    pNewNode->m_forward[curLevel] = updates[curLevel]->m_forward[curLevel]; updates[curLevel]->m_forward[curLevel] = pNewNode; } // 增加元素个数 ++m_count; return true; } bool SkipList::Remove(int data) { 
    auto* pCurNode = m_pHead; if (IsEmpty()) return false; // 需要更新下一跳指针的节点 std::vector<SkipListNode*> updates(m_level); for (int curLevel = m_level - 1; curLevel >= 0; --curLevel) { 
    if (nullptr == pCurNode->m_forward[curLevel]) { 
    updates[curLevel] = pCurNode; continue; } while (pCurNode->m_forward[curLevel]->m_data < data) { 
    pCurNode = pCurNode->m_forward[curLevel]; if (nullptr == pCurNode->m_forward[curLevel]) break; } updates[curLevel] = pCurNode; } if (data != pCurNode->m_forward[0]->m_data) { 
    // 没有该节点 return false; } // 待删除元素 auto* pRmoveNode = pCurNode->m_forward[0]; // 将原来指向待删除元素的指针指向待删除元素的下一个元素 for (int curLevel = m_level - 1; curLevel >= 0; --curLevel) { 
    if (updates[curLevel]->m_forward[curLevel] == pRmoveNode) updates[curLevel]->m_forward[curLevel] = pRmoveNode->m_forward[curLevel]; } // 修改层高,将为空的层删除 for (int curLevel = m_level - 1; curLevel >= 0; --curLevel) { 
    if (nullptr == m_pHead->m_forward[curLevel]) --m_level; } m_pHead->m_forward.resize(m_level + 1); // 元素个数-1 --m_count; } 

main.cpp:

#include  
     #include  
     #include  
     int main() { 
    SkipList skipList; std::vector<int> datas; datas.reserve(100); for (int idx = 0; idx < 100; ++idx)datas.push_back(idx); std::random_shuffle(datas.begin(), datas.end()); for (auto& data : datas) skipList.Insert(data); skipList.Print(); std::cout << "--------------------------------" << std::endl; for (auto& data : datas) skipList.Remove(data); skipList.Print(); return 0; } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176569.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午9:36
下一篇 2026年3月26日 下午9:36


相关推荐

  • 字节和字符区别

    字节和字符区别字节字节 说白了就是 byte 二进制数据 通常在读取图片 声音 可执行文件需要用字节数组来保存文件 在下载文件也是用 byte 数组来做临时的缓冲器接收文件内容 字符机器只知道字节 而字符却是语义上的单位 它是有编码的 一个字符可能编码成 1 个 2 个甚至 3 个 4 个字节 这跟字符集编码有关系 英文字母和数字是单字节 但汉字这些自然语言中的字符是多字节的 一个字节只能表示 255 个字符 不可能用于全球

    2026年3月20日
    2
  • 在Python中,输出格式:%d , m , %-6d, d , %.6f的一些区分

    在Python中,输出格式:%d , m , %-6d, d , %.6f的一些区分和 C C 编程语言一样 d 普通的整数输出 i 1sum 0whilei lt 100 sum ii 1print 1 到 100 的和为 d sum 1 到 100 的和为 5050 6d 整数输出 整数的宽度是 6 位 若不足 6 位 左边补空格 1i 12sum 03whilei lt

    2026年2月21日
    1
  • JavaScript高级编程

    JavaScript高级编程

    2021年11月13日
    39
  • 关于scrollIntoView的使用

    关于scrollIntoView的使用当输入框被键盘挡住时,可以使用scrollIntoView让输入框回到视野&lt;divref="inputBox"style="height:400px;"&gt;//一定要设置高度才会有效果  &lt;inputtype="text"@focus="intoview()"/&gt;&lt;/div&gt;intoview:function(){  this.$r

    2022年6月24日
    50
  • 腾讯元宝双模型发布:混元T1升级,DeepSeek V3代码能力提升

    腾讯元宝双模型发布:混元T1升级,DeepSeek V3代码能力提升

    2026年3月13日
    3
  • linux vim命令详解_linux中查看文件内容的命令

    linux vim命令详解_linux中查看文件内容的命令 vim是linux中最基本的操作vim常用模式1、命令模式2、插入模式3、底行模式4、可视化模式,命令模式按v进入5、替换模式,命令模式下按r进入1、插入模式默认进入文件打开的是命令模式在这个模式下是不能插入字符的按“i”键,然后就进入到插入模式了,屏幕下面有个“–INSERT–”标识,很明显的现在就能写你的文档了,写完后按“Esc"键就…

    2025年7月2日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号