跳跃表

 

理解:跳跃表是一种索引(1/2概率)随机功能的链表,因此存在两个后继。

struct node {
        node(int val = INT_MIN) :value(val), up(nullptr), down(nullptr), left(nullptr), right(nullptr) {} // 结构体构造
        int value;
        struct node* down; // 下
        struct node* right; // 右
    };

由于单向链表寻找前个节点只能从链表head再次遍历,我们采用双向链表。

struct node {
        node(int val = INT_MIN) :value(val), up(nullptr), down(nullptr), left(nullptr), right(nullptr) {}
        int value;
        // 设置4个方向上的指针
        struct node* up; // 上
        struct node* down; // 下
        struct node* left; // 左
        struct node* right; // 右
    };

 

头文件

#pragma once
#ifndef SKIPLIST_INT_H_
#define SKIPLIST_INT_H_
#include <cstdlib>     /* srand, rand */
#include <ctime>       /* time */
#include <climits>     /* INT_MIN */
/* 简单跳跃表,它允许简单的插入和删除元素,并提供O(logn)的查询时间复杂度。 */
/*
    SkipList_Int的性质
    (1) 由很多层结构组成,level是通过一定的概率随机产生的,基本是50%的产生几率。
    (2) 每一层都是一个有序的链表,默认是升序,每一层的链表头作为跳点。
    (3) 最底层(Level 1)的链表包含所有元素。
    (4) 如果一个元素出现在Level i 的链表中,则它在Level i 之下的链表也都会出现。
    (5) 每个节点包含四个指针,但有可能为nullptr。
    (6) 每一层链表横向为单向连接,纵向为双向连接。
*/
// Simple SkipList_Int 表头始终是列表最小的节点
class SkipList_Int {
private:
    /* 节点元素 */
    struct node {
        node(int val = INT_MIN) :value(val), up(nullptr), down(nullptr), left(nullptr), right(nullptr) {}
        int value;
        // 设置4个方向上的指针
        struct node* up; // 上
        struct node* down; // 下
        struct node* left; // 左
        struct node* right; // 右
    };
private:
    node* head; // 头节点,查询起始点
    int lvl_num; // 当前链表层数
    /* 随机判断 */
    bool randomVal();
public:
    SkipList_Int() : lvl_num(1) {
        head = new node();
    }
    /* 插入新元素 */
    void insert(int val);
    /* 查询元素 */
    bool search(int val);
    /* 删除元素 */
    void remove(int val);
};
#endif // !SKIPLIST_INT_H_

源代码 

#include "skip_list.h"

static unsigned int seed = NULL; // 随机种子

bool SkipList_Int::randomVal() {
    if (seed == NULL) {
        seed = (unsigned)time(NULL);
    }
    ::srand(seed);
    int ret = ::rand() % 2;
    seed = ::rand();
    if (ret == 0) {
        return true;
    }
    else {
        return false;
    }
}

void SkipList_Int::insert(int val) {
    /* 首先查找L1层 */
    node* cursor = head;
    node* new_node = nullptr;
    while (cursor->down != nullptr) {
        cursor = cursor->down;
    }
    node* cur_head = cursor; // 当前层链表头
    while (cursor->right != nullptr) {
        if (val < cursor->right->value && new_node == nullptr) {
            new_node = new node(val);
            new_node->right = cursor->right;
            cursor->right = new_node;
        }
        cursor = cursor->right; // 向右移动游标
    }
    if (new_node == nullptr) {
        new_node = new node(val);
        cursor->right = new_node;
    }
    /* L1层插入完成 */
    /* 上层操作 */
    int cur_lvl = 1; // 当前所在层
    while (randomVal()) {
        cur_lvl++;
        if (lvl_num < cur_lvl) { // 增加一层
            lvl_num++;
            node* new_head = new node();
            new_head->down = head;
            head->up = new_head;
            head = new_head;
        }
        cur_head = cur_head->up; // 当前链表头上移一层
        cursor = cur_head; // 继续获取游标
        node* skip_node = nullptr; // 非L1层的节点
        while (cursor->right != nullptr) {
            if (val < cursor->right->value && skip_node == nullptr) {
                skip_node = new node(val);
                skip_node->right = cursor->right;
            }
            cursor = cursor->right;
        }
        if (skip_node == nullptr) {
            skip_node = new node(val);
            cursor->right = skip_node;
        }
        while (new_node->up != nullptr) {
            new_node = new_node->up;
        }
        /* 连接上下两个节点 */
        skip_node->down = new_node;
        new_node->up = skip_node;
    }
}

bool SkipList_Int::search(int val) {
    node* cursor = nullptr;
    if (head == nullptr) {
        return false;
    }
    /* 初始化游标指针 */
    cursor = head;
    while (cursor->down != nullptr) { // 第一层循环游标向下
        while (cursor->right != nullptr) { // 第二层循环游标向右
            if (val <= cursor->right->value) { // 定位元素:于当前链表发现可定位坐标则跳出循环...
                break;
            }
            cursor = cursor->right;
        }
        cursor = cursor->down;
    }
    while (cursor->right != nullptr) { // L1层循环开始具体查询
        if (val > cursor->right->value) {
            cursor = cursor->right; // 如果查找的值大于右侧值则游标可以继续向右
        }
        else if (val == cursor->right->value) { // 如果等于则表明已经找到节点
            return true;
        }
        else if (val < cursor->right->value) { // 如果小于则表明不存在该节点
            return false;
        }
    }
    return false; // 完成遍历返回false;
}

void SkipList_Int::remove(int val) {
    node* cursor = head; // 获得游标
    node* pre_head = nullptr; // 上一行的头指针,删除行时使用
    while (true) {
        node* cur_head = cursor; // 当前行头指针
        if (pre_head != nullptr) {
            cur_head->up = nullptr;
            pre_head->down = nullptr; // 解除上下级的指针
            delete pre_head;
            pre_head = nullptr; // 指针归0
            lvl_num--; // 层数-1
            head = cur_head; // 重新指定起始指针
        }
        while (cursor != nullptr && cursor->right != nullptr) { // 在当前行中查询val
            if (val == cursor->right->value) {
                node* delptr = cursor->right;
                cursor->right = cursor->right->right;
                delete delptr; // 析构找到的节点
            }
            cursor = cursor->right;
        }
        if (cur_head->right == nullptr) { // 判断当前行是否还存在其它元素,如果不存在则删除该行并将整个跳跃表降维
            pre_head = cur_head;
        }
        if (cur_head->down == nullptr) {
            break;
        }
        else {
            cursor = cur_head->down;
        }
    }
}

int main() {
    SkipList_Int test1;
    for (int i = 0; i < 10; i++) {
        test1.insert(i);
    }
    bool search_label = test1.search(12);
    search_label = test1.search(21);
    test1.remove(1);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值