什么是skiplist
skiplist是一种多级的排序链表,为什么要是多级的呢?
考虑一个链表如下:
1 —> 2—> 5—> 10—> 20—> 37
如果想要查询10,我们要从头查询4次,这就是O(n)的查询效率,这样的效率太低了,怎么办呢?我们可以按一定算法选出一些节点当作索引,比如:选择1、5、20作为一级索引,这样这个表就变成了:
1 ———-> 5———–> 20——->|
1 —> 2—> 5—> 10—> 20—> 37
我们再查询,就可以从上面的层级开始遍历,查询1、5,5的下一节点是20 已经大于10,所以要跳到下一层,还是从5开始,5的下一节点是10,找到了。
路径是1、5、10。当节点多且建立更多级合理的索引时,查询效率会达到O(lgn),与平衡树接近。最关键的是实现简单。
skiplist在redis和leveldb中都有应用。leveldb 的数据在内存中的格式是memtable,而memtable就是用skiplist实现的。
leveldb中的skiplist
template<typename Key, class Comparator>
class SkipList {
private:
struct Node;
public:
explicit SkipList(Comparator cmp, Arena* arena);
// Insert key into the list.
// REQUIRES: nothing that compares equal to key is currently in the list.
void Insert(const Key& key);
// Returns true iff an entry that compares equal to key is in the list.
bool Contains(const Key& key) const;
// Iteration over the contents of a skip list
... //其余细节省略
};
这个skiplist的接口很简单,也可以发现这个skiplist没有del或者update,只有insert,这是因为,leveledb中的删除只是insert(key, deleteflag),当memtable到达一定容量时,会变成immutable(只读) memtable,再生成一个memtable,后台线程会将immutable memtable dump成 sstable(磁盘文件格式),然后再compation sstable,这时会删掉无用的数据。所以这个skiplist也不需要del接口。下面来看 insert接口,
template<typename Key, class Comparator>
void SkipList<Key,Comparator>::Insert(const Key& key) {
Node* prev[kMaxHeight]; //记录遍历的路径
Node* x = FindGreaterOrEqual(key, pref); //查找位置
// Our data structure does not allow duplicate insertion
assert(x == NULL || !Equal(key, x->key));//不允许重复数据
int height = RandomHeight(); //在skiplist中生成的随机高度
if (height > GetMaxHeight()) { //如果生成的高度大于定义好的最大高度
for (int i = GetMaxHeight(); i < height; i++) {
prev[i] = head_; //补充路径
}
max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
}
x = NewNode(key, height);//为当前的key 生成新的node
for (int i = 0; i < height; i++) { //从最低级 到随机高度 插入新列,最低层的数据最全,然后级越高,数据越少。所以如果高层级有此节点,则低层级也一定有。
// NoBarrier_SetNext() suffices since we will add a barrier when
// we publish a pointer to "x" in prev[i].
//这两行代码的效果是这样 原数据是 1--> 3 现在插入2
//则先 2-->3 ,然后再 1-->2。简单的链表插入
x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
prev[i]->SetNext(i, x);
}
}
从最高层级往下遍历。
template<typename Key, class Comparator>
typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)
const {
Node* x = head_;
int level = GetMaxHeight() - 1;
while (true) {
Node* next = x->Next(level);//当前层级往后查找
if (KeyIsAfterNode(key, next)) {//如果key大于当前节点
// Keep searching in this list
x = next;
} else { //小于
if (prev != NULL) prev[level] = x;//记录
if (level == 0) {
return next; //找到了位置
} else {
// Switch to next list
level--;// 向下一级查找
}
}
}
}