简介
leveldb 存取数据,都在用 MemTable 这个结构体,而 MemTable 核心在于 level::MemTable::Table,也就是 typedef SkipList<const char*, KeyComparator> level::MemTable::Table
。 SkipList 看名字就知道,跳表,是一种数据结构,允许快速查询一个有序连续元素的数据链表。这是一种 “以空间换取时间” 的一种做法,值得注意的是,这些链表都是有序的。
关于这个跳表,我查了一下作者(William Pugh)给出的解析:
Skip lists are a data structure that can be used in place of balanced trees. Skip lists use probabilistic balancing rather than strictly enforced balancing and as a result the algorithms for insertion and deletion in skip lists are much simpler and significantly faster than equivalent algorithms for balanced trees.
跳表是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的 插入和删除的工作是比较简单的。
也就是说核心在于随机算法,一个靠谱的随机算法对跳表是非常重要的。
现在我们来一边用代码加图解来分析一下跳表魅力!
跳表数据存储模型
跳表数据结构如下:
template <typename Key, typename Value>
class SkipList {
private:
struct Node; // 声明节点结构体
public:
explicit SkipList();
private:
int level_; // 跳表层数
Node* head_; // 跳表头部节点列表
unit32_t rnd_; // 随机数因子
// 生成节点方法
Node* NewNode(int level, const Key& key, const Value& value);
Node* FindGreaterOrEqual(const Key& key, Node** prev) const;
};
节点数据结构:
template <typename Key, typename Value>
struct SkipList<Key, Value>::Node {
explicit Node(const Key& k, const Value& v) : key(k), value(v) {}
Key key;
Value value;
void SetNext(int i, Node* x);
Node* Next(int i);
private:
struct Node* forward_[1]; // 节点数组列表,这个比较重要,后面会详细介绍,如果不理解这个变量,就很难理解跳表了
}
通过图来看一下总体结构
ps:图中虚线链接表述数组关系,实现标识指针链表关系
上图假设 level 为 4 等级的一个跳表图,,forward_ 变量是一个指针数组,一边指向下一个节点(黑色填充箭头)的链表,一边又是这些链表的数组(透明填充箭头)这样的一个数据结构形成了我们需要的一个链表。
后面我们会称为图中竖向(dowm)节点为节点数组
,横向(left)的节点为节点链表
初始化跳表
首先为了实现这个结构,我们来初始化跳表
enu