跳表 Skiplist

跳表

跳表(Skiplist)是一种多层级链表,相比一般的链表,有更高的查找效率,可比拟二叉查找树,平均期望的查找、插入、删除时间复杂度都是O(logn)。

跳表:解决单链表查询效率慢的问题

跳表vs红黑树,

  1. 跳表和红黑树的插入、删除、查找效率都是O(logN),都可以顺序遍历所有元素(红黑树通过中序遍历)。红黑树更稳定一些,跳表恶化是存在概率的,虽然概率极低。
  2. 跳表实现简单,但是浪费了很多空间。红黑树实现麻烦,但是没有使用额外的空间。
  3. 跳表区间查找很方便,redis中的zset实现区间查找就是用的跳表。

代码实现:

#pragma once

#include <vector>
#include <iostream>
#include <stdlib.h>

// 跳表命名空间
namespace skipList{
    // 跳表类
    class SkipList
    {
    public:
        // 构造函数,接受一个可选参数level,表示跳表的层数,默认为4
        SkipList(size_t level = 4) : level_(level){
            head_ = new SkipNode(-1, level);
        }
        // 析构函数 遍历跳表的每个节点,并释放它们占用的内存空间
        ~SkipList() { 
            SkipNode* curr = head_;
            while (curr != nullptr) {
            SkipNode* next = curr->forward_[0];
            delete curr;
            curr = next;
            } 
        }
    
    public:
        // 查找节点
        bool SearchNode(int key);  
        // 添加节点
        void AddNode(int key); 
        // 删除节点    
        bool EraseNode(int key); 
        // 打印跳表  
        void PrintfSkipList();     

    private:
        // 随机生成节点的层数
        size_t RandomLevel(){
            size_t level = 1;
            while (rand() % 2){
                level++;
            }
            // 返回的层数不能超过跳表的最大层数
            return (level > level_) ? level_ : level;
        }
        // 定义跳表节点
        struct SkipNode{
            SkipNode(int key, size_t level) : key_(key),forward_(level, nullptr){ }
            int key_;  // 键值
            std::vector<SkipNode*> forward_;  // 向前指针数组,用于构建每一层的链表
        };

        size_t level_;    // 跳表的层数
        SkipNode* head_;  // 跳表的头节点指针
    }; 
}

// 查找节点
bool skipList::SkipList::SearchNode(int key){
    SkipNode* head = head_;
    for (int i = level_ - 1; i >= 0; --i){
        while (head->forward_[i] != nullptr && head->forward_[i]->key_ < key){
            head = head->forward_[i];
        }
        if (head->forward_[i] != nullptr && head->forward_[i]->key_ == key){
            return true;
        }
    }
    return false;
}

// 新增节点
void skipList::SkipList::AddNode(int key){
    size_t level = RandomLevel();
    SkipNode* node = new SkipNode(key, level);
    SkipNode* head = head_;
    for (int i = level_ - 1; i >= 0; --i){
        while (head->forward_[i] != nullptr && head->forward_[i]->key_ < key){
            head = head->forward_[i];
        }
        if (level > i){
            node->forward_[i] = head->forward_[i];
            head->forward_[i] = node;
        }
    }
}

// 删除节点
bool skipList::SkipList::EraseNode(int key){
    SkipNode* head = head_;
    SkipNode* node = nullptr;
    for (int i = level_ - 1; i >= 0; --i){
        while (head->forward_[i] != nullptr && head->forward_[i]->key_ < key){
            head = head->forward_[i];
        }
        if (head->forward_[i] != nullptr && head->forward_[i]->key_ == key){
            node = head->forward_[i];
            head->forward_[i] = node->forward_[i];
        }
    }
    if (node == nullptr){
        return false;
    } else {
        delete node;
        node = nullptr;
        return true;
    }
}

// 遍历跳表

void skipList::SkipList::PrintfSkipList(){
    for (int i = level_ - 1; i >= 0; --i){
        SkipNode* head = head_;
        while (head->forward_[i] != nullptr){
            if (head->forward_.size() > i){
                std::cout << head->forward_[0]->key_ << "\t";
            }else{
                std::cout << "\t"; 
            }
            head = head->forward_[0];
        }
        std::cout << std::endl;
    }
}

测试:

#include "skiplist.hpp"
#include <time.h>
using namespace std;

int main()
{
    // 实例化
    skipList::SkipList skip_list;
    
    // 随机生成跳表
    srand(time(0));
    for (int i = 0; i < 10; ++i){
        skip_list.AddNode(rand() % 100);
    }

    // 打印
    skip_list.PrintfSkipList();

    // 增加节点并打印
    skip_list.AddNode(20);
    skip_list.AddNode(30);
    skip_list.AddNode(40);
    skip_list.PrintfSkipList();

    // 删除节点并打印
    skip_list.EraseNode(30);
    skip_list.PrintfSkipList();

    // 防止控制台一闪而过
    getchar();
    return 0;
}
posted @ 2023-08-23 21:35  洋綮  阅读(21)  评论(0)    收藏  举报