跳表c++模板类实现

一.介绍

        跳表是一种为了提高搜索效率的数据结构,提高了链表的查询速度。

        主要原理是每隔一段距离,就设定一个索引节点,索引节点的值就是对应节点的值,这样就可以通过索引节点,在链表上跳跃前进而不是一个一个找,如果目标值大于等于当前索引节点,而小于下一索引节点,则说明目标值在两个索引之间,向下一层来到真正的链表继续向后遍历就可以找到目标。而对索引链表再次创建索引,就可以更进一步提高效率,所以最终跳表的结构为多层链表,除最底层为数据外,其余层都为索引,每层索引节点数量不固定,一般让上层节点的数量为下层节点的一半,这样就达到了logn的查询时间复杂度。

#include<random>
#include<iostream>
#include<time.h>
#include<set>
using namespace std;
template<typename T>
class Skiplist 
{
public:
    static constexpr int Maxlevel = 16;
    //最大层数
    static constexpr double P = 0.6;
    //到上一层的概率

    random_device rd;
    mt19937 gen;
    uniform_real_distribution<> dis;
    //随机数

    struct node//储存的结构体
    {
        T data;//储存数据
        node* next[Maxlevel + 1];//指向后面节点

        node()//初始化
        {
            for (int i = 0; i <= Maxlevel; i++)
            {
                next[i] = nullptr;
            }
        }
    };

    node* head;//头节点





    Skiplist() {//初始化
        head = new node;
        gen = mt19937(rd());
        dis = uniform_real_distribution<>(0, 1);
    }

    //查询函数
    bool search(T target) {
        node* now = head;
        for (int i = Maxlevel; i >= 1; i--)
        {//每一层都找到小于目标值的最后一个数,再往下
            while (now->next[i] != nullptr && now->next[i]->data < target)
                now = now->next[i];
        }
        //now现在是第1层小于目标值的最后一个数
        if (now->next[1] == nullptr) return false;//没有下一个,失败
        if (now->next[1]->data != target) return false;//下一个不是目标值失败
        return true;//其余情况成功
    }


    //生成随机层数,每次添加时,看这个节点在几层
    int randlevel()
    {
        int res = 1;
        while (res < Maxlevel && dis(gen) < P)
        {
            res++;
        }
        return res;
    }
    

    //添加函数
    void add(T num) {
        node* temp = new node;//添加的节点
        temp->data = num;

        node* now = head;

        node* pre[Maxlevel + 1];//记录前置节点
        int level = randlevel();//获取随机层数

        for (int i = Maxlevel; i >= 1; i--)
        {
            while (now->next[i] != NULL && now->next[i]->data < num)
                now = now->next[i];
            pre[i] = now;//查询时,记录每一个前置节点
        }

        for (int i = level; i >= 1; i--)//在level到第一层都加上这个节点
        {
            temp->next[i] = pre[i]->next[i];
            pre[i]->next[i] = temp;
        }

    }


    //删除节点
    bool erase(T num) {
        node* now = head;
        node* pre[Maxlevel + 1];
        //先查询一遍这个节点是否存在
        for (int i = Maxlevel; i >= 1; i--)
        {
            while (now->next[i] != nullptr && now->next[i]->data < num)
                now = now->next[i];
            pre[i] = now;//记录前置节点
        }
        if (now->next[1] == nullptr) return false;
        if (now->next[1]->data != num) return false;


        //将目标节点对应层数删除
        node* temp = NULL;//释放内存
        for (int i = Maxlevel; i >= 1; i--)
        {
            if (pre[i]->next[i] != nullptr)
            {
                //只删除目标节点
                if (pre[i]->next[i]->data != num)
                    continue;
                
                temp = pre[i]->next[i];
                pre[i]->next[i] = pre[i]->next[i]->next[i];
                
            }
                
        }
        if(temp != NULL)
            delete temp;//出来一起释放,都是同一个节点
        temp = nullptr;
        return true;
    }

    void print()
    {
        node* now = head;
        for (int i = Maxlevel; i >= 1; i--)
        {
            node* now = head;
            while (now->next[i] != NULL)
            {
                cout << now->next[i]->data << " ";
                now = now->next[i];
            }
            cout << endl;
        }
    }
};
int main()
{
    Skiplist<int> s;
    for (int i = 1; i <= 100; i++)
    {
        s.add(i);
    }
    s.print();
    s.erase(5);
    s.print();
    s.erase(20);
    s.print();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值