算法【跳表】|

一、简介

跳表实际上是对链表进行改造,以支持类似于二分搜索的算法;
内部包含n个元素,其查询和插入的平均时间复杂度为O(logN);
其结果简单,为多级单链表,使用空间来换取时间(需要额外将近一倍空间),甚至可以用来替代红黑树(redis中的有序集合);
【查询】:首先,在最上层(最稀疏)开始查找,不断跳转到下一个层次,直到找到元素;

1、如何生成跳表

通过类似二分的思想对其进行生成多级索引,查询即可根据前后的区间来锁定;
跳表的高度:log(2)n-1;

在这里插入图片描述

跳表消耗的空间这么大,值得嘛???

以下看到需要用到的额外空间将近多出一倍,但在实际的开发过程中,索引节点将记录关键值和指针,不需要存储对象,以此来减
少对空间的损耗;

插入数据

首先查找到该位置,在往内部插入数据;
在插入数据中为了避免后续造成某个区间的索引个数过多,我们需要为此进行维护;
- 让随机的方式来决定新插入节点来决定索引的层数;

删除数据

将原始链表中删除以及索引删除即可;

2、代码

/** 链表节点 */
template<class T>
struct Node {
    T data = -1;
    vector<Node*> forward;
    int maxLevel;

    Node() { forward.resize(16); }

    Node(T val, int level) : data(val), maxLevel(level) { forward.resize(16); }

    string toString() {
        stringstream ss;
        ss << "{ data: " << data
           << "; levels: " << maxLevel
           << " }";
        return ss.str();
    }
};

template<class T>
class SkipList {

public:
    SkipList() {}
    SkipList(Node<T> *node) : head(node) {
        srand(time(0));

    }
    ~SkipList() {}

    /** 查找函数 */
    Node<T>* find(int val) {
        Node<T>* p = head;
        /* 从最上层开始查找 */
        for (int i = levelCnt - 1; i >= 0 ; --i) {
            while (p->forward[i] != nullptr && p->forward[i]->data < val ) {
                p = p->forward[i];
            }
        }
        auto tmp = p->forward[0];
        if(tmp != nullptr && tmp->data == val) {
            return tmp;
        }else {
            return nullptr;
        }
    }

    /** 插入函数 */
    void insert(int val) {
        int level = randomLevel();
        Node<T>* newNode = new Node<T>(val, level);
        vector<Node<T>*> update;
        update.resize(level);
        for (int i = 0; i < level; ++i) {
            update[i] = head;
        }

        Node<T> *p = head;
        for(int i= level - 1; i>=0; --i) {
            while (p->forward[i] != nullptr && p->forward[i]->data < val) {
                p = p->forward[i];
            }
            update[i] = p;
        }

        for(int i=0; i<level; ++i) {
            newNode->forward[i] = update[i]->forward[i];
            update[i]->forward[i] = newNode;
        }
        if(levelCnt < level) levelCnt = level;
    }

    /** 删除函数 */
    void erase(int val) {
        vector<Node<T>*> update;
        update.resize(levelCnt);
        Node<T>* p = head;
        for(int i=levelCnt - 1; i>=0; --i) {
            while (p->forward[i] != nullptr && p->forward[i]->data < val) {
                p = p->forward[i];
            }
            update[i] = p;
        }
        if(p->forward[0] != nullptr && p->forward[0]->data == val) {
            for(int i=levelCnt-1; i>=0; --i) {
                if(update[i]->forward[i] != nullptr && update[i]->forward[i]->data == val) {
                    update[i]->forward[i] = update[i]->forward[i]->forward[i];
                }
            }
        }
        while (levelCnt > 1 && head->forward[levelCnt] == nullptr) {
            levelCnt--;
        }
    }

    /**
     * 设置等概率返回层数
     * */
    int randomLevel() {
        int level = 1;
        while ((rand() & 0xFFFF) < (0.25 * 0xFFFF)) {
            ++level;
        }
        return min(level, MAX_LEVEL);
    }

    /** 打印函数 */
    void myPrint() {
        for(int i=0; i<head->maxLevel; ++i) {
            Node<int> *tmp = head;
            cout << "this level: " << i << endl;
            while (tmp->forward[i] != nullptr) {
                cout << tmp->forward[i]->data << " ";
                tmp = tmp->forward[i];
            }
            cout << endl;
        }
    }

private:
    static float SKIPLIST_P;
    static int MAX_LEVEL;
    int levelCnt = 4;
    Node<T>* head;
};

template<class T>
float SkipList<T>::SKIPLIST_P = 0.25;
template<class T>
int SkipList<T>::MAX_LEVEL = 16;


void test_func(){
    Node<int> node(1, 6);
    SkipList<int> sl(&node);
    for(int i=0;i<101; ++i)
        sl.insert(i);

    sl.myPrint();
    auto tmp = sl.find(29);
    cout << tmp->toString() << endl;
    sl.erase(29);
    sl.myPrint();
}

int main() {
    test_func();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值