数据结构(9)-- 跳表


删除节点

int slDelete(skiplist *sl, double score)

{

skiplistNode *update[SKIPLIST_MAXLEVEL];

skiplistNode *sn;

int i;

sn = sl->head;

for(i=sl->level-1;i>=0;i–)

{

while(sn->forward[i]&&sn->forward[i]->score<score){

sn = sn->forward[i];

}

update[i] = sn;

}

sn = sn->forward[0];

if(sn->score != score)

{

return -1;

}

for(i=0;ilevel;i++)

{

if(update[i]->forward[i] != sn){

break;

}

update[i]->forward[i] = sn->forward[i];

}

free(sn);

while(sl->level>1&&sl->head->forward[sl->level-1] == NULL){

sl->level–;

}

sl->length–;

return 0;

}


销毁跳表

销毁整个调表的时候,从level=1销毁即可,别忘记释放head和skiplist。

void slFree(skiplist *sl)

{

skiplistNode* sn = sl->head,*st;

st = sn->forward[0];

free(sn);

while(st)

{

sn = st->forward[0];

free(st);

st = sn;

}

free(sl);

}


接下来我们看点其它的,碧如说跳表与redis。(我第一次接触跳表也是在redis的源码中)


为什么Redis要用跳表来实现有序集合?


性能. 主要是对标AVL. 但是AVL实现复杂,对于频繁的增删操作极大可能造成子树的平衡操作,这样很明显就会浪费性能。

请看开发者说的,他为什么选用skiplist The Skip list:

There are a few reasons:1) They are not very memory intensive. It’s up to you basically. Changing parameters about the probability of a node to have a given number of levels will make then less memory intensive than btrees.2) A sorted set is often target of many ZRANGE or ZREVRANGE operations, that is, traversing the skip list as a linked list. With this operation the cache locality of skip lists is at least as good as with other kind of balanced trees.3) They are simpler to implement, debug, and so forth. For instance thanks to the skip list simplicity I received a patch (already in Redis master) with augmented skip lists implementing ZRANK in O(log(N)). It required little changes to the code.About the Append Only durability & speed, I don’t think it is a good idea to optimize Redis at cost of more code and more complexity for a use case that IMHO should be rare for the Redis target (fsync() at every command). Almost no one is using this feature even with ACID SQL databases, as the performance hint is big anyway.About threads: our experience shows that Redis is mostly I/O bound. I’m using threads to serve things from Virtual Memory. The long term solution to exploit all the cores, assuming your link is so fast that you can saturate a single core, is running multiple instances of Redis (no locks, almost fully scalable linearly with number of cores), and using the “Redis Cluster” solution that I plan to develop in the future.


在并发环境下skiplist有另外一个优势,红黑树在插入和删除的时候可能需要做一些rebalance的操作,这样的操作可能会涉及到整个树的其他部分,而skiplist的操作显然更加局部性一些,锁需要盯住的节点更少,因此在这样的情况下性能好一些。


我的代码实现


#include

#include

#include<time.h>

using namespace std;

//跳表节点类

class sk_list_node {

public:

sk_list_node(int val)

:val(val),

next(nullptr),

next_floor(nullptr)

{}

sk_list_node(sk_list_node* node)

:val(node->get_value()),

next(nullptr),

next_floor(nullptr)

{

}

void set_next(sk_list_node* node) {

this->next = node;

}

void set_next_floor_node(sk_list_node* node) {

this->next_floor = node;

}

int get_value() { return this->val; }

sk_list_node* get_next() {

return this->next;

}

sk_list_node* get_next_floor() {

return this->next_floor;

}

int equal(sk_list_node* node) {

if (node->get_value() == val) {

return 0;

}

else if(node->get_value() > val){

return 1;

}

else {

return -1;

}

}

private:

int val; //当前节点值

sk_list_node* next; //下一个节点

sk_list_node* next_floor; //下一层对应节点

};

//跳表类

class sk_list {

public:

sk_list(int f,int p)

:floors(f),

probability§,

head(new sk_list_node(INT_MIN))

{

if (p <= f) { //概率要比楼层大,因为下面我要玩点好玩的

p = f + 1;

}

//初始化第一列

sk_list_node* temp = head;

for (int i = 0; i < f; i++) {

temp->set_next_floor_node(new sk_list_node(INT_MIN));

temp = temp->get_next_floor();

}

}

//寻找某节点

bool search_node(sk_list_node* node){

sk_list_node* temp = head;

while (temp) {

if (temp->equal(node) == 0) {

return true;

}

else if (temp->equal(node) == 1) {

return false;

}

else {

if (temp->get_next() && temp->get_next()->equal(node) == 1) {

//如果下一节点大于当前节点,则往下

temp = temp->get_next_floor();

}

//否则不论小或等都往后

temp = temp->get_next();

}

}

return false;

}

void insert_(sk_list_node* node) {

int floor = floors - get_probabily();

insert_floor(search_front(node, floor), node, floor);

}

void delete_(sk_list_node* node) {

sk_list_node *temp = search_front(node);

if (temp == nullptr) {

return;

}

else {

while (temp) {

if (temp->get_next()->equal(node) == 0) {

temp->set_next(temp->get_next()->get_next());

temp = temp->get_next_floor(); //删除时也要横向推进

}

temp = temp->get_next();

}

}

}

private:

int get_probabily() {

//根据概率获取层数

int num = 0;

int p = 0;

srand(time(NULL));

while (p == 0 && num <= floors) {

p = rand() % probability;

–probability; //放缓概率递减的速度

++num;

}

return num;

}

//寻找某节点的前驱结点

//供插入用

sk_list_node* search_front(sk_list_node* node,int floor) {

sk_list_node* temp = head;

while (temp) {

if (temp->equal(node) == 0) { //如果就这么巧,那就不存了吧

return nullptr;

}

else {

if (temp->get_next()) {

if (temp->get_next()->equal(node) == 1) {

//如果下一节点大于当前节点,则往下

if (floor == 0) { //如果楼层够了,就返回吧

return temp;

}

temp = temp->get_next_floor();

–floor;

}

temp = temp->get_next();

}

else { //如果说当前层没有后继节点了

if (temp->get_next_floor() == nullptr) { //最尾巴了

return temp;

}

temp = temp->get_next_floor(); //那就往下一层

}

}

}

return nullptr;

}

//供删除用

sk_list_node* search_front(sk_list_node* node) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

虽然面试套路众多,但对于技术面试来说,主要还是考察一个人的技术能力和沟通能力。不同类型的面试官根据自身的理解问的问题也不尽相同,没有规律可循。

上面提到的关于这些JAVA基础、三大框架、项目经验、并发编程、JVM及调优、网络、设计模式、spring+mybatis源码解读、Mysql调优、分布式监控、消息队列、分布式存储等等面试题笔记及资料

有些面试官喜欢问自己擅长的问题,比如在实际编程中遇到的或者他自己一直在琢磨的这方面的问题,还有些面试官,尤其是大厂的比如 BAT 的面试官喜欢问面试者认为自己擅长的,然后通过提问的方式深挖细节,刨根到底。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
aed303032d36.jpg" alt=“img” style=“zoom: 33%;” />

总结

虽然面试套路众多,但对于技术面试来说,主要还是考察一个人的技术能力和沟通能力。不同类型的面试官根据自身的理解问的问题也不尽相同,没有规律可循。

[外链图片转存中…(img-2hmK4h5u-1712938331322)]

[外链图片转存中…(img-SVuZmOYh-1712938331322)]

上面提到的关于这些JAVA基础、三大框架、项目经验、并发编程、JVM及调优、网络、设计模式、spring+mybatis源码解读、Mysql调优、分布式监控、消息队列、分布式存储等等面试题笔记及资料

有些面试官喜欢问自己擅长的问题,比如在实际编程中遇到的或者他自己一直在琢磨的这方面的问题,还有些面试官,尤其是大厂的比如 BAT 的面试官喜欢问面试者认为自己擅长的,然后通过提问的方式深挖细节,刨根到底。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值