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();
}
相关推荐
Inverse1621 小时前
C语言_动态内存管理
c语言·数据结构·算法
Yushan Bai2 小时前
ORACLE RAC环境REDO日志量突然增加的分析
数据库·oracle
躺着听Jay2 小时前
Oracle-相关笔记
数据库·笔记·oracle
瀚高PG实验室2 小时前
连接指定数据库时提示not currently accepting connections
运维·数据库
运维成长记3 小时前
mysql数据库-中间件MyCat
数据库·mysql·中间件
尘客.3 小时前
DataX从Mysql导数据到Hive分区表案例
数据库·hive·mysql
liang_20263 小时前
【HT周赛】T3.二维平面 题解(分块:矩形chkmax,求矩形和)
数据结构·笔记·学习·算法·平面·总结
进击的小白菜4 小时前
LeetCode 153. 寻找旋转排序数组中的最小值:二分查找法详解及高频疑问解析
数据结构·算法·leetcode
TiDB 社区干货传送门4 小时前
从开发者角度看数据库架构进化史:JDBC - 中间件 - TiDB
数据库·oracle·中间件·tidb·数据库架构
虾球xz4 小时前
游戏引擎学习第280天:精简化的流式实体sim
数据库·c++·学习·游戏引擎