https://leetcode-cn.com/problems/design-skiplist/
思路:原理参见。
class Listnode
{
public:
//val-值 count-出现的次数
int val,count;
//forwards[i]代表在第i级(level)的情况下 该节点的下一节点 1代表最低级 相当于普通链表\
//这里还有一个隐含信息:该节点是第forwards.size() 级的节点
vector<Listnode*> forwards;
Listnode(int v=-1,int level=0):val(v),count(1),forwards(level,nullptr){}
int get_level(){ return forwards.size(); }
};
class Skiplist {
public:
//限制跳表的最大level
const int max_level=16;
//目前最高level
int cur_level;
//跳表头节点
Listnode *head;
Skiplist():head(new Listnode(-1,max_level)) {}
~Skiplist() { delete head; }
//得到一个level
int random_level()
{
int level=1;
while((rand()&1)&&level<max_level)
++level;
return level;
}
//查找指定节点
Listnode* _search(int target)
{
//当前节点 下一节点
Listnode *cur=head,*nxt;
for(int i=cur_level-1;i>=0;i--)
{
while((nxt=cur->forwards[i])&&nxt->val<target)
cur=nxt;
//找到 返回其前驱
if(nxt&&nxt->val==target)
return nxt;
}
return nullptr;
}
//查找指定节点的前驱 为了便于获得后继 需要level记录层级
Listnode* _search_before(int target,int &level)
{
//当前节点 下一节点
Listnode *cur=head,*nxt;
for(int i=cur_level-1;i>=0;i--)
{
while((nxt=cur->forwards[i])&&nxt->val<target)
cur=nxt;
//找到
if(nxt&&nxt->val==target)
{
level=i;
return cur;
}
}
return nullptr;
}
//查找target是否存在
bool search(int target) {
return _search(target)!=nullptr;
}
//添加num到跳表中
void add(int num) {
//查找指定节点
Listnode *cur=_search(num);
//若存在 直接递增计数即可
if(cur)
++cur->count;
//否则需要在跳表中新增节点
else
{
//为新加节点随机一个level
int level=random_level();
if(cur_level<level)
cur_level=level;
//新节点
Listnode *newnode=new Listnode(num,level);
cur=head;
Listnode *nxt;
//注意此处循环要从cur_level开始 而不要从level开始
//因为level可能远小于cur_level 如果此时num是一个较大的数 会浪费很多时间
for(int i=cur_level-1;i>=0;i--)
{
while((nxt=cur->forwards[i])&&nxt->val<num)
cur=nxt;
//在第i+1级新增节点 注意i+1要<=level 即i<level
if(i<level)
{
newnode->forwards[i]=nxt;
cur->forwards[i]=newnode;
}
}
}
}
//从跳表中删除num
bool erase(int num) {
int level;
//待删节点前驱
Listnode *cur=_search_before(num,level);
//若存在
if(cur)
{
Listnode *del=cur->forwards[level];
level=del->get_level();
//需要递减其count 若递减后count=0 需要从跳表中移除
if(--del->count==0)
{
Listnode *nxt;
for(int i=level-1;i>=0;i--)
{
while((nxt=cur->forwards[i])&&nxt!=del)
cur=nxt;
if(nxt)
cur->forwards[i]=nxt->forwards[i];
}
//回收空间
delete del;
}
return true;
}
return false;
}
};
/**
* Your Skiplist object will be instantiated and called as such:
* Skiplist* obj = new Skiplist();
* bool param_1 = obj->search(target);
* obj->add(num);
* bool param_3 = obj->erase(num);
*/