用C++实现跳跃表(代码+详细注释+用例测试)

前言

今天依旧是记录算法分析作业的一天:)

用C++,实现跳跃表的查找增加和删除
是在《数据结构与算法分析(C++版)》(第三版)这本书后附加的代码的基础上改的。

跳跃表具体内容我也不多说了,可以参考Redis之跳跃表实现『数据结构』跳跃表 这两篇文章的图文描述。

我就谈谈具体实现代码:

头文件代码

SkipList.h

#include <random>

using namespace std;

#define MAXLEVEL 9

int randomLevel(void) { //随机分配级数
	int level = 0;
	while (rand()%2 == 0) level++;
	return level;
}

//结点
template <typename Key, typename E>
class SkipNode {
public:
    int myLevel;
    Key k; // 成员对象
    E it;  //值
    SkipNode** forward; // 前进指针,指向表尾方向

    //两个构造函数
    SkipNode() {
        myLevel = MAXLEVEL;
        forward = new SkipNode * [MAXLEVEL + 1];
        for (int i = 0; i <= MAXLEVEL; i++)
            forward[i] = NULL;
    }
    SkipNode(Key key, E r, int level) {
        myLevel = level;
        k = key;
        it = r;
        forward = new SkipNode * [level + 1];
        for (int i = 0; i <= level; i++)
            forward[i] = NULL;
    }

    ~SkipNode() { delete[] forward; }
};

//跳跃表
template <typename Key, typename E>
class SkipList {
private:
    SkipNode<Key,E>* head;
    //unordered_map<Key, E>* head;  //相当于实现一个哈希表,方便查找
    int level;  // 表中层数最大的节点的层数
    int reccount;  // 表中节点的数量
    void AdjustHead(int& level) { 
        level = MAXLEVEL; 
    }

public:

    SkipList() { //构造函数
        head = new SkipNode<Key, E>;
        level = MAXLEVEL;
        reccount = 0;
    }

    E find(const Key& k) const {  //按照序号找某个结点
        SkipNode<Key, E>* x = head;         // 定义一个指针
        for (int i = level; i >= 0; i--)
            while ((x->forward[i] != NULL) &&
                (k > x->forward[i]->k))
                x = x->forward[i];
        x = x->forward[0];  // 如果存在,移至根节点
        if ((x != NULL) && (k == x->k)) return x->it;  //找到了,返回该序号结点对应的值
        return NULL;
    }

    void insert(const Key& k, const E& it) {
        int i;
        SkipNode<Key, E>* x = head;   // Start at header node
        int newLevel = randomLevel(); // 给新节点定义层数
        if (newLevel > level) {     // New node is deepest in list
            AdjustHead(newLevel);     // Add null pointers to header
            level = newLevel;
        }
        SkipNode<Key, E>* update[MAXLEVEL + 1]; // Track level ends
        for (i = level; i >= 0; i--) {   // 在所有级数上进行适当的链接
            while ((x->forward[i] != NULL) && (x->forward[i]->k < k))
                x = x->forward[i];
            update[i] = x;           // x为要插入的前一个值的位置
        }
        x = new SkipNode<Key, E>(k, it, newLevel);   // New node
        for (i = 0; i <= newLevel; i++) {          // 插入
            x->forward[i] = update[i]->forward[i]; 
            update[i]->forward[i] = x;          
        }
        reccount++;
    }

    bool remove(const Key& k)
    {
        //cout << "Remove not implemented\n"; return false;
        int i;
        SkipNode<Key, E>* x = head;   
        SkipNode<Key, E>* update[MAXLEVEL + 1];
        int flag = 0; //为0,表示不是最后一位
        for (i = level; i >= 0; i--) {   // 查找所有级数
            while ((x->forward[i] != NULL) && (x->forward[i]->k < k))
                x = x->forward[i];
            update[i] = x;           // x为要插入的前一个值的位置
            if (x->forward[i] == NULL) {//如果x是最后一位
                flag = 1;
                if (x->k != k) //没有这个数
                    return false; 
            }
        }
        for (i = 0; i <= level; i++) {
            if (flag == 1) {
                update[i]->forward[i] = NULL;
            }
            else {
                update[i]->forward[i] = update[i]->forward[i]->forward[i];
            }
        }
        reccount--;
        return true;
    }

    int size() { return reccount; }

    void print() const {
        cout << "Print a skiplist with " << reccount << " nodes\n";
        for (SkipNode<Key, E>* temp = head; temp != NULL;
            temp = temp->forward[0]) {
            if (temp->it != NULL)
                cout << "temp->k is " << temp->k << "\n";
            else cout << "temp->k is NULL\n";
            for (int i = 0; i <= temp->myLevel; i++)
                if (temp->forward[i] == NULL)
                    cout << " point to NULL\n";
                else
                    cout << " point to " << temp->forward[i]->it << "\n";
        }
        cout << endl;
    }
};

源文件代码

//用例测试
skipMain.cpp

#include<iostream>
#include<stdlib.h>
#include "skiplist.h"
using namespace std;
int main()
{
    SkipList<int, int*> sl;
    int* it;
    cout << "Size: " << sl.size() << "\n";

    sl.insert(100, new int(100));
    cout << "Size: " << sl.size() << "\n";
    sl.print();
    
    if ((sl.remove(15)) != false)
        cout << "Removed 15 successed " << endl;
    else cout << "No key 15\n";
   
    sl.insert(15, new int(15));
    cout << "Size: " << sl.size() << "\n";
    sl.print();
    
    if ((it = sl.find(20)) != NULL)
        cout << "Found " << it << endl;
    else cout << "No key 20\n";
    if ((it = sl.find(15)) != NULL)
        cout << "Found 15: " << it << endl<<endl;
    else cout << "No key 15\n";
    sl.print();

    if ((sl.remove(20)) != false)
        cout << "Removed 20 successed " << endl;
    else cout << "No key 20\n";
    cout << "Now, insert 20\n";
    sl.insert(20, new int(20));
    sl.print();
   
    //测试
    sl.insert(700, new int(700));
    sl.insert(350, new int(350));
    sl.insert(201, new int(201));
    sl.insert(170, new int(170));
    sl.insert(151, new int(151));
    sl.insert(190, new int(190));
    sl.insert(1000, new int(1000));
    sl.insert(900, new int(900));
    sl.insert(950, new int(950));
    sl.insert(10, new int(10));
    sl.print();

    if ((it = sl.find(1000)) != NULL)
        cout << "Found " << it << endl;
    else cout << "No key 1000\n";
    if ((it = sl.find(999)) != NULL)
        cout << "Found " << it << endl;
    else cout << "No key 999\n";

    //测试
    cout << "Finally, test iterator\n";
    sl.insert(3500, new int(3500));
    sl.insert(2010, new int(2010));
    sl.insert(1700, new int(1700));
    sl.insert(1510, new int(1510));
    sl.insert(1900, new int(1900));
    sl.insert(10000, new int(10000));
    sl.insert(9000, new int(9000));
    sl.insert(9500, new int(9500));
    sl.insert(100, new int(100));
    sl.print();
    return 0;
}

总结

并没有用到什么技巧和复杂的结构,主要是理解实现的过程就行(奈何我逻辑不行,在网上看了好多讲解的文章

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值