redis核心数据结构——跳表项目设计与实现(跳表结构插入数据、删除数据、展示数据)

数据的插入

首先来看需求

你的任务是实现 SkipList 类中搜索节点和插入节点的成员函数。

插入节点成员函数签名:int insert_element(const K key, const V value)

向跳表中插入一对数据,如果跳表中已存在该键值对,则不做任何操作,返回 1,如果不存在该键值对,则将该键值对插入到跳表中,返回 0。

参数说明: K key:键; V value:值。

搜索节点成员函数签名:bool search_element(K key)

在跳表中查询键值为 key 的键值对,如果跳表中已存在该键值对,则返回 true,否则返回 false。

参数说明: K key:键。

跳表的插入其实和链表插入差不多,不同之处就在于每一层都需要插入,查找也是一样,每一层都要进行查找。这两个操作其实不难,难的是数组越界问题的排查,主要是之前写的那篇文章里,节点构造函数中需要给forwards数组分配动态内存。

因为这个改了半天。

cpp 复制代码
template <typename K, typename V>
Node<K, V>::Node(const K k, const V v, int level) {
    this->key = k;
    this->value = v;
    this->node_level = level;
    this->forward = new Node<K, V> *[level + 1];
    memset(this->forward, 0, sizeof(Node<K, V> *) * (level + 1));
};

另外就是每次创建新节点时需要随机分配层数,加上一开始用两个变量分别记录最大层数和当前层数,分配后该层数不能超过最大层数,且如果大于当前层数,需要将当前层数进行更新。

代码如下:

cpp 复制代码
#include<stdlib.h>
#include <iostream>
#include <cstring>

template<typename K, typename V>
class Node {
private:
    K key;
    V val;
    int node_level;
    
public:
    Node** forwards;
    
public:
    Node(K inkey, V value, int level): key(inkey), val(value), 
        node_level(level),forwards(nullptr) 
    {
        this->forwards = new Node<K, V>*[node_level+1];
        memset(this->forwards, 0, sizeof(Node<K,V>*)*(node_level+1));
    }
    ~Node(){
        delete forwards;
    };
    K getKey() const {
        return key;
    }
    V get_value() const {
        return val;
    }
    int getLevel() const {
        return node_level;
    }
    void set_value(V value) {
        val = value;
    }
    
};

template<typename K, typename V>
class SkipList {
private:
    Node<K,V>* HeadNode = nullptr;
    int _maxlevel = 0;
    int temp_level = 0;
public:
    SkipList(int maxlevel = 500) {
        _maxlevel = maxlevel;
        HeadNode = new Node<K, V>(K(),V(),maxlevel);
    }
    ~SkipList() { delete HeadNode; _maxlevel = 0; temp_level = 0; }
    int getRandomLevel() {
        srand((int)time(0));
        int k = 1;
        while (rand() % 2) {
            k++;
        }
        k = (k < _maxlevel) ? k : _maxlevel;
        return k;
    }
    int insert_element(const K key, const V value) {
        int flag = 0;
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            cur = HeadNode;
            while (cur) {
                if (cur->getKey() == key) {
                    flag = 1;
                    cur->set_value(value);
                }
                cur = cur->forwards[curlevel]; 
            }
            curlevel--;
        }
        if (flag == 1) return 1;
        Node<K, V>* newNode = new Node<K,V>(key, value, getRandomLevel());
        if (temp_level < newNode->getLevel()) temp_level = newNode->getLevel();
        curlevel = newNode->getLevel();
        while (curlevel) {
            Node<K,V>* prev = HeadNode;
            cur = HeadNode->forwards[curlevel];
            while (cur) {
                if (cur->getKey() > newNode->getKey()) {
                    prev->forwards[curlevel] = newNode;
                    newNode->forwards[curlevel] = cur;
                    break;
                } 
                cur = cur->forwards[curlevel];
                prev = prev->forwards[curlevel];
            }   
            if (!cur)
                prev->forwards[curlevel] = newNode;
            curlevel--;
        }
        return 0;
    }
    bool search_element(K key) {
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            cur = HeadNode->forwards[curlevel];
            while (cur) {
                if (cur->getKey() == key) return true;
                cur = cur->forwards[curlevel]; 
            }
            curlevel--;
        }
        return false;
    }
};


int main() {
    SkipList<int, int> mySkipList;
    int n, m;
    std::cin >> n >> m;
    while (n--) {
        int k, v, r;
        std::cin >> k >> v;
        r = mySkipList.insert_element(k,v);
        if (r == 0) std::cout << "Insert Success" << std::endl;
        else std::cout << "Insert Failed" << std::endl;
    }
    while (m--) {
        int k;
        std::cin >> k;
        if (mySkipList.search_element(k)) std::cout << "Search Success" << std::endl;
        else std::cout << "Search Failed" << std::endl;
    }
}

数据的删除

先来看下需求:

你的任务是实现 SkipList 类中删除节点成员函数。

成员函数签名:delete_element(K key)

此成员函数需要从跳表中删除键为 key 的节点。如果该键存在,则删除对应的节点;如果不存在,则不进行任何操作。

参数说明: K key:要删除的元素的键,其中 K 是键的类型。

思路和单纯的链表删除差不多

实现函数代码如下:

cpp 复制代码
void delete_element(K key) {
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            Node<K,V>* prev = HeadNode;
            cur = HeadNode->forwards[curlevel];
            while (cur) {
                if (cur->getKey() == key) {
                    prev->forwards[curlevel] = cur->forwards[curlevel];
                    break;
                }
                cur = cur->forwards[curlevel];
                prev = prev->forwards[curlevel];
            }
            curlevel--;
        }
    }

数据的展示

首先来看下需求:

你的任务是实现 SkipList 类中的打印跳表的成员函数。

成员函数签名:void display_list() 此成员函数专门负责按照层次结构将跳表的内容输出到控制台。

输出格式如下所述:

  • 从最顶层开始,逐层向下打印跳表的索引链
  • 每一层的打印输出首先标注该层的级别,接着依次打印该层上每个节点的键值对
  • 每个键值对以键:值的形式表示,键值对之间使用;分隔,确保信息的清晰可读
  • 每个层级的所有键值对信息占据一行,以便于视觉上的层次区分

输出格式示例:

Level 1: 1:3;3:5;

Level 0: 1:3;2:4;3:5;

三部分整合后代码如下:

cpp 复制代码
#include<stdlib.h>
#include <iostream>
#include <cstring>

template<typename K, typename V>
class Node {
private:
    K key;
    V val;
    int node_level;
    
public:
    Node** forwards;
    
public:
    Node(K inkey, V value, int level): key(inkey), val(value), 
        node_level(level),forwards(nullptr) 
    {
        this->forwards = new Node<K, V>*[node_level+1];
        memset(this->forwards, 0, sizeof(Node<K,V>*)*(node_level+1));
    }
    ~Node(){
        delete forwards;
    };
    K getKey() const {
        return key;
    }
    V get_value() const {
        return val;
    }
    int getLevel() const {
        return node_level;
    }
    void set_value(V value) {
        val = value;
    }
    
};

template<typename K, typename V>
class SkipList {
private:
    Node<K,V>* HeadNode = nullptr;
    int _maxlevel = 0;
    int temp_level = 0;
public:
    SkipList(int maxlevel = 500) {
        _maxlevel = maxlevel;
        HeadNode = new Node<K, V>(K(),V(),maxlevel);
    }
    ~SkipList() { delete HeadNode; _maxlevel = 0; temp_level = 0; }
    int getRandomLevel() {
        srand((int)time(0));
        int k = 1;
        while (rand() % 2) {
            k++;
        }
        k = (k < _maxlevel) ? k : _maxlevel;
        return k;
    }
    int insert_element(const K key, const V value) {
        int flag = 0;
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            cur = HeadNode;
            while (cur) {
                if (cur->getKey() == key) {
                    flag = 1;
                    cur->set_value(value);
                }
                cur = cur->forwards[curlevel]; 
            }
            curlevel--;
        }
        if (flag == 1) return 1;
        Node<K, V>* newNode = new Node<K,V>(key, value, getRandomLevel());
        if (temp_level < newNode->getLevel()) temp_level = newNode->getLevel();
        curlevel = newNode->getLevel();
        while (curlevel) {
            Node<K,V>* prev = HeadNode;
            cur = HeadNode->forwards[curlevel];
            while (cur) {
                if (cur->getKey() > newNode->getKey()) {
                    prev->forwards[curlevel] = newNode;
                    newNode->forwards[curlevel] = cur;
                    break;
                } 
                cur = cur->forwards[curlevel];
                prev = prev->forwards[curlevel];
            }   
            if (!cur)
                prev->forwards[curlevel] = newNode;
            curlevel--;
        }
        return 0;
    }
    bool search_element(K key) {
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            cur = HeadNode->forwards[curlevel];
            while (cur) {
                if (cur->getKey() == key) return true;
                cur = cur->forwards[curlevel]; 
            }
            curlevel--;
        }
        return false;
    }
    void delete_element(K key) {
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            Node<K,V>* prev = HeadNode;
            cur = HeadNode->forwards[curlevel];
            while (cur) {
                if (cur->getKey() == key) {
                    prev->forwards[curlevel] = cur->forwards[curlevel];
                    break;
                }
                cur = cur->forwards[curlevel];
                prev = prev->forwards[curlevel];
            }
            curlevel--;
        }
    }
    void print() {
        Node<K,V>* cur = HeadNode;
        int curlevel = temp_level;
        while (curlevel) {
            cur = HeadNode->forwards[curlevel];
            std::cout << "Level " << curlevel-1 << ": ";
            while (cur) {
                std::cout << cur->getKey() << ":" << cur->get_value() << ';';
                cur = cur->forwards[curlevel];
            }
            std::cout << std::endl;
            curlevel--;
        }
    }
};


int main() {
    SkipList<int, int> mySkipList;
    int n,k,m;
    std::cin >> n >> k >> m;
    while (n--) {
        int key, v, r;
        std::cin >> key >> v;
        r = mySkipList.insert_element(key,v);
        if (r == 0) std::cout << "Insert Success" << std::endl;
        else std::cout << "Insert Failed" << std::endl;
    }
    while (k--) {
        int key;
        std::cin >> key;
        mySkipList.delete_element(key);
    }
    while (m--) {
        int k;
        std::cin >> k;
        if (mySkipList.search_element(k)) std::cout << "Search Success" << std::endl;
        else std::cout << "Search Failed" << std::endl;
    }
    mySkipList.print();
}
相关推荐
老邓计算机毕设2 小时前
SSM学生选课系统xvbna(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·学生选课系统·ssm 框架·高校教学管理
難釋懷3 小时前
SpringDataRedis数据序列化器
redis·缓存
枷锁—sha3 小时前
【PortSwigger Academy】SQL 注入绕过登录 (Login Bypass)
数据库·sql·学习·安全·网络安全
逍遥德5 小时前
PostgreSQL 中唯一约束(UNIQUE CONSTRAINT) 和唯一索引(UNIQUE INDEX) 的核心区别
数据库·sql·postgresql·dba
工业甲酰苯胺5 小时前
字符串分割并展开成表格的SQL实现方法
数据库·sql
科技块儿6 小时前
IP定位技术:游戏反外挂体系中的精准识别引擎
数据库·tcp/ip·游戏
鱼跃鹰飞6 小时前
Leetcode347:前K个高频元素
数据结构·算法·leetcode·面试
衫水6 小时前
[特殊字符] MySQL 常用指令大全
数据库·mysql·oracle
卓怡学长6 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
好评1246 小时前
【C++】二叉搜索树(BST):从原理到实现
数据结构·c++·二叉树·二叉搜索树