当前位置:网站首页>跳表的实现
跳表的实现
2022-07-28 15:00:00 【今天也要写bug、】
跳表的实现
一般跳表会设计一个最大层数maxLevel(在Redis中为32)的限制,其次会设置一个多增加一层的概率p(在Redis中为0.25)。
产生越高的节点层数,概率越低。
- 节点层数至少为1。而大于1的节点层数,满足一个概率分布。
- 节点层数恰好等于1的概率为1-p。
- 节点层数大于等于2的概率为p,而节点层数恰好等于2的概率为p(1-p)。
- 节点层数大于等于3的概率为p2,而节点层数恰好等于3的概率为p2 *(1-p)。
- 节点层数大于等于4的概率为p3,而节点层数恰好等于4的概率为p3*(1-p)。
当p=1/2时,每个节点所包含的平均指针数目为2。当p=1/4时,每个节点所包含的平均指针数目为1.33。
struct SkipNode
{
//跳表的一个节点
SkipNode(int val,int level)
{
_val=val;
_next.resize(level,nullptr);
}
//当前节点的值
int _val;
//当前节点指向下一个节点的指针数组
vector<SkipNode*>_next;
};
class Skiplist {
private:
typedef struct SkipNode Node;
//带一个头结点
Node* _head;
//最大高度为32
size_t _max_level=32;
double _p=0.25;
public:
Skiplist() {
//头结点一开始为1层
_head=new Node(-1,1);
srand(time(0));
}
bool search(int target) {
Node*cur=_head;
//当前的层数,用下标表示
int level=_head->_next.size()-1;
//如果查找到小于0的下标,说明没有找到
while(level>=0)
{
//target和cur->next[level]->_val比较
//比它小向下走,比它大向右走
//当前节点下一个位置是空时也往下走
if((cur->_next[level]&&cur->_next[level]->_val>target)||cur->_next[level]==nullptr)
{
level--;
}
else if(cur->_next[level]->_val<target)
{
cur=cur->_next[level];
}
else//相等,找到了
{
return true;
}
}
return false;
}
//找寻num之前的节点的指针
vector<Node*> FindPreNode(int num)
{
//保存插入位置每一层,前一个节点的指针
vector<Node*>prev(_max_level,_head);
Node*cur=_head;
//然后找插入的位置
int level=_head->_next.size()-1;
while(level>=0)
{
//如果比下一个位置大或者等于,往下走
//我们将该值插到相等值的最前面
if((cur->_next[level]&&cur->_next[level]->_val>=num)||cur->_next[level]==nullptr)
{
//往下走的时候,记录这些值,方便插入的时候使用
prev[level]=cur;
level--;
}
//比下一个位置的值小于,往右走
else if(cur->_next[level]&&cur->_next[level]->_val<num)
{
cur=cur->_next[level];
}
}
return prev;
}
void add(int num) {
//记录应该插入的位置
vector<Node*> prev=FindPreNode(num);
//获取随机的层数
int n=RandomLevel();
Node*newnode=new Node(num,n);
//判断获取的层数和当前头节点的层数
//当前头结点的层数有可能比新获取的层数小
if(_head->_next.size()<n)
{
_head->_next.resize(n,nullptr);
}
//链接prev和newnode
for(int i=0;i<n;i++)
{
newnode->_next[i]=prev[i]->_next[i];
prev[i]->_next[i]=newnode;
}
}
int RandomLevel()
{
int level=1;
//RAND_MAX是rand()产生的最大值,乘上0.25,可以保证有0.25的几率进入while循环
while(rand()<=RAND_MAX*_p&&level<_max_level)
{
++level;
}
return level;
}
bool erase(int num) {
//找到每一层的前一个
vector<Node*> prev=FindPreNode(num);
//第一层不存在,或者第一层下一个位置比num大,比如1(prev) 5(prev[0]->_next)这种情况
//说明num不在表中,比如num=3
if(prev[0]->_next[0]==nullptr||prev[0]->_next[0]->_val!=num)
{
//没找到这个值
return false;
}
else
{
//prev[0]->_next[0]=num,此时需要删掉这个节点
Node* del=prev[0]->_next[0];
//del节点每一层的前后指针链接起来
for(int i=0;i<del->_next.size();++i)
{
prev[i]->_next[i]=del->_next[i];
}
delete del;
//删完以后,头结点可能需要降低高度
//比如删除的节点高度是10,删完之后,整个表最高的节点只有5,但是头结点仍然为10
int i=_head->_next.size()-1;
while(i>=0)
{
//从上往下找到第一个非空的节点,然后删掉它
if(_head->_next[i]==nullptr)
{
i--;
}
else
{
break;
}
}
_head->_next.resize(i+1);
}
return true;
}
};
skiplist跟平衡搜索树和哈希表的对比
- skiplist相比平衡搜索树(AVL树和红黑树)对比,都可以做到遍历数据有序,时间复杂度也差不多。skiplist的优势是:a、skiplist实现简单,容易控制。平衡树增删查改遍历都更复杂。 b、skiplist的额外空间消耗更低。平衡树节点存储每个值有三叉链,平衡因子/颜色等消耗。skiplist中p=1/2时,每个节点所包含的平均指针数目为2;skiplist中p=1/4时,每个节点所包含的平均指针数目为1.33;
- skiplist相比哈希表而言,就没有那么大的优势了。相比而言a、哈希表平均时间复杂度是O(1),比skiplist快。b、哈希表空间消耗略多一点。skiplist优势如下:a、遍历数据有序 b、skiplist空间消耗略小一点,哈希表存在链接指针和表空间消耗。c、哈希表扩容有性能损耗。d、哈希表再极端场景下哈希冲突高,效率下降厉害,需要红黑树补足接力。
边栏推荐
- Camera continuous shooting automatic test shell script
- How to turn on and off flight mode through ADB
- Basic structure and operation principle of solar street lamp
- 带你来浅聊一下!单商户功能模块汇总
- 数据实时反馈技术
- Pytorch - optimize model parameters
- A wave of operation to solve the error problem of Laya scene editor
- js 队列
- 2021 Kent interview question 1
- Where is the RDS MySQL read-only instance of Alibaba cloud created
猜你喜欢

12V pulse speed measurement to 24V level signal conversion transmitter

High speed counter to rs485modbus RTU module ibf150

Open light input / relay output rs485/232 remote data acquisition IO module ibf70

Encoder high speed pulse counter Modbus RTU module ibf150

MLX90640 红外热成像仪测温传感器模块开发笔记(八)

High precision absolute angle sensor application high speed angle monitoring

One channel encoder, two channels Di speed measurement, RS485 serial port connected to one channel do alarm module ibf151

Perception of life

1路编码器2路DI转速测量RS485串口连接1路DO报警模块IBF151

MicTR01 Tester 开发套件(振弦采集读数仪)使用说明
随机推荐
Two special functions (arrow function and method)
Thermistor PT100, NTC to 0-10v/4-20ma converter
Vm501 development kit development version single vibrating wire sensor acquisition module geotechnical engineering monitoring
JS array (summary)
5-channel di/do relay output remote IO acquisition module Modbus tcp/ibf95
Multifunctional mixed signal AI acquisition / switching value di/do acquisition to rs485/232/modbus module
2021 Kent interview question 3
Framework customization series (VI) -- shield fallbackhome mobile phone from pop-up during startup and directly enter the launcher
Using SYSTEMd to manage services
数据实时反馈技术
高精度绝对角度传感器应用高速度角度监测
多功能混合信号AI采集/开关量DI/DO采集转RS485/232/MODBUS模块
RF module wireless transceiver rf63u chip application data transmission and infrastructure network
Rust 入门指南(rustup, cargo)
如何快速接入统一的认证鉴权体系
远距离串口服务器( 适配器)UART/I2C/1-Wire/SPI PS304常见问题及注意事项
IFD-x 微型红外成像仪(模块)的温度测量和成像精度
Open light input / relay output rs485/232 remote data acquisition IO module ibf70
Pyqt5 rapid development and practice 5.1 tables and trees
Software architecture and design (IX) -- component based architecture