什么是跳表
如下所示就是一个随机生成的跳跃表。每一个结点不单单只包含指向下一个结点的指针,可能包含很多个指向后续结点的指针,这样就可以跳过一些不必要的结点,从而加快查找、删除等操作。对于一个链表内每一个结点包含多少个指向后续元素的指针,这个过程是通过一个随机函数生成器得到。
跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。插入/删除/搜索 都是 O(log n)
。
跳表是一个随机化的数据结构,可以被看做二叉树的一个变种,它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,目前在Redis和LeveIDB中都有用到。
时间复杂性
当跳表中有n个元素时,搜索、插入、删除操作的复杂性均为O(n+MaxLevel)。在最坏情况下,可能只有一个MaxLevel级元素,且余下的所有元素均在0级链上。i>0时,在i级链上花费的时间为(MaxLevel),而在0级链上花费的时间为O(n)。尽管最坏情况下的性能较差,但跳表仍不失为一种有价值的数据描述方法。其每种操作(搜索、插入、删除)的平均复杂性均为O(logn),
空间复杂性
至于空间复杂性,注意到最坏情况下所有元素都可能是MaxLevel级,每个元素都需要
MaxLevel+1个指针。因此,除了存储n个元素(也就是n*sizeof(element)),还需要存储链指针(所需空间为O(n*MaxLevel))。不过,一般情况下,只有n*p个元素在1级链上,n*p2个元素在2级链上,n*pi在i级链上。因此指针域的平均值(不包括头尾节点的指针)是n/(1-p)。因此虽然最坏情况下空间需求比较大,但平均的空间需求并不大。当p=0.5时,平均空间需求(加上n个节点中的指针)大约是2n个指针的空间。
性能比较
实现代码如下
tg_skiplist.h
#ifndef TG_SKIPLIST_H
#define TG_SKIPLIST_H
#include <random>
#include <memory>
#include <vector>
#include<array>
#include<functional>
template<typename KeyType,typename ValueType>
class tg_skiplist
{
#define CONST_MAX_LEVEL 31
struct inner_node
{
inner_node(KeyType key, ValueType value, int level):key(key),value(value)
{
forward.reserve(level+1);
for(int i = 0; i < level+1; i++)
{
forward[i] = nullptr;
}
}
KeyType key;
ValueType value;
std::vector<std::shared_ptr<inner_node>> forward;
};
typedef std::shared_ptr<inner_node> inner_node_ptr;
public:
tg_skiplist():_level(0),_size(0)
{
KeyType k;
ValueType v;
_head = std::make_shared<inner_node>(k, v, CONST_MAX_LEVEL-1);
}
~tg_skiplist()=default;
bool insert(const KeyType& key,const ValueType& value)
{
std::array<inner_node_ptr, CONST_MAX_LEVEL> arr;
auto p = _head;
for(int i = _level; i >= 0; i--)
{
while(p->forward[i] && p->forward[i]->key < key)
{
p = p->forward[i];
}
arr[i] = p;
}
p = p->forward[0];
if(p && p->key == key)
{
return false;
}
int lev = random_level();
if(lev > _level)
{
lev = ++_level;
arr[lev] = _head;
}
auto ptr = std::make_shared<inner_node>(key, value, lev);
for(int i = lev; i >= 0; i--)
{
p = arr[i];
ptr->forward[i] = p->forward[i];
p->forward[i] = ptr;
}
++_size;
return true;
}
std::shared_ptr<ValueType> erase(const KeyType& key)
{
std::array<inner_node_ptr, CONST_MAX_LEVEL> arr;
auto p = _head;
for(int i = _level; i >= 0; i--)
{
while(p->forward[i] && p->forward[i]->key < key)
{
p = p->forward[i];
}
arr[i] = p;
}
p = p->forward[0];
if(p && p->key == key)
{
for(int i = 0; i <= _level; i++)
{
if(arr[i]->forward[i] != p)
{
break;
}
arr[i]->forward[i] = p->forward[i];
}
if(_level > 0 && _head->forward[_level] == nullptr)
{
_level--;
}
_size--;
return std::make_shared<ValueType>(p->value);
}
return nullptr;
}
std::shared_ptr<ValueType> find(const KeyType& k)
{
auto p = _head;
for(int i = _level; i >= 0; i--)
{
while(p->forward[i] && p->forward[i]->key < k)
{
p = p->forward[i];
}
}
p = p->forward[0];
if(p && k == p->key)
{
return std::make_shared<ValueType>(p->value);
}
return nullptr;
}
int size() const
{
return _size;
}
int level() const
{
return _level + 1;
}
void visit(std::function<void(ValueType&)> fun)
{
inner_node_ptr p = _head;
while(p->forward[0])
{
fun(p->forward[0]->value);
p = p->forward[0];
}
}
private:
int random_level()
{
int lev = 0;
while(1)
{
if(_random()%2)
lev++;
else
break;
}
return lev < CONST_MAX_LEVEL ? lev : CONST_MAX_LEVEL-1;
}
int _level;
int _size;
std::random_device _random;
inner_node_ptr _head;
};
#endif // TG_SKIPLIST_H
测试代码
#include "tg_skiplist.h"
#include <iostream>
struct node
{
node()=default;
node(int k, double value):val(value + 0.5),key(k)
{
}
double val;
int key;
};
void print(node& n)
{
std::cout<< n.key << "\t" << n.val <<std::endl;
}
int main()
{
tg_skiplist<int,node> list;
std::random_device random;
random();
for(int i = 0; i < 50; i++)
{
int k = random() % 50;
auto tmp = std::make_shared<node>(k, k);
list.insert(k, *tmp);
}
std::cout<<"#####################################"<<std::endl;
list.visit(print);
std::cout<< list.size() << "\t" << list.level() <<std::endl;
std::cout<<"##################查找###################"<<std::endl;
for(int i = 0; i < 10; i++)
{
auto ptr = list.find(i);
if(ptr)
{
print(*ptr);
}
else
{
std::cout<< "找不到: key=" << i <<std::endl;
}
}
std::cout<<"################删除#####################"<<std::endl;
auto ptr = list.erase(5);
if(ptr)
{
print(*ptr);
}
std::cout<<"##################查找###################"<<std::endl;
for(int i = 0; i < 10; i++)
{
auto ptr = list.find(i);
if(ptr)
{
print(*ptr);
}
else
{
std::cout<< "找不到: key=" << i <<std::endl;
}
}
}
测试结果
#####################################
0 0.5
2 2.5
3 3.5
4 4.5
5 5.5
6 6.5
9 9.5
10 10.5
11 11.5
12 12.5
13 13.5
14 14.5
15 15.5
16 16.5
17 17.5
18 18.5
19 19.5
20 20.5
23 23.5
26 26.5
28 28.5
29 29.5
30 30.5
31 31.5
33 33.5
34 34.5
35 35.5
38 38.5
40 40.5
41 41.5
42 42.5
43 43.5
46 46.5
48 48.5
49 49.5
35 6
##################查找###################
0 0.5
找不到: key=1
2 2.5
3 3.5
4 4.5
5 5.5
6 6.5
找不到: key=7
找不到: key=8
9 9.5
################删除#####################
5 5.5
##################查找###################
0 0.5
找不到: key=1
2 2.5
3 3.5
4 4.5
找不到: key=5
6 6.5
找不到: key=7
找不到: key=8
9 9.5