在跳表 上 中介绍了跳表的基本结构,接下来将要介绍跳表的迭代器和其内部实现的方法。
Iterator
-跳表的迭代器跳表的迭代器实现非常简单,调用了跳表内部的一些实现方法。
// Iteration over the contents of a skip list class Iterator { public: // Initialize an iterator over the specified list. // The returned iterator is not valid. explicit Iterator(const SkipList* list); // Returns true iff the iterator is positioned at a valid node. bool Valid() const; // Returns the key at the current position. // REQUIRES: Valid() const Key& key() const; // Advances to the next position. // REQUIRES: Valid() void Next(); // Advances to the previous position. // REQUIRES: Valid() void Prev(); // Advance to the first entry with a key >= target void Seek(const Key& target); // Position at the first entry in list. // Final state of iterator is Valid() iff list is not empty. void SeekToFirst(); // Position at the last entry in list. // Final state of iterator is Valid() iff list is not empty. void SeekToLast(); //私有成员 private: const SkipList* list_; Node* node_; // Intentionally copyable }; //... //迭代器的构造函数 template<typename Key, class Comparator> inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) { list_ = list; node_ = nullptr; } //判断是否合法 template<typename Key, class Comparator> inline bool SkipList<Key,Comparator>::Iterator::Valid() const { return node_ != nullptr; } //返回key template<typename Key, class Comparator> inline const Key& SkipList<Key,Comparator>::Iterator::key() const { assert(Valid()); return node_->key; } //默认从最底层链路跳到next的位置 //之前说过,第0层包含了所有的key template<typename Key, class Comparator> inline void SkipList<Key,Comparator>::Iterator::Next() { assert(Valid()); node_ = node_->Next(0); } //跳到前一个Node的位置 template<typename Key, class Comparator> inline void SkipList<Key,Comparator>::Iterator::Prev() { // Instead of using explicit "prev" links, we just search for the // last node that falls before key. assert(Valid()); //FindLessThan是skipList的一个方法,后面会详细介绍 node_ = list_->FindLessThan(node_->key); if (node_ == list_->head_) { node_ = nullptr; } } //Seek是追踪的意思 template<typename Key, class Comparator> inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) { //设置当前节点为与target的key相等或比target大的node //FindGreaterOrEqual也是skiplist的一个函数 node_ = list_->FindGreaterOrEqual(target, nullptr); } //追踪到头部 template<typename Key, class Comparator> inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() { //在skiplist中有一个head_成员 node_ = list_->head_->Next(0); } //追踪到尾部 template<typename Key, class Comparator> inline void SkipList<Key,Comparator>::Iterator::SeekToLast() { node_ = list_->FindLast(); if (node_ == list_->head_) { node_ = nullptr; } }
NewNode
template<typename Key, class Comparator> typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::NewNode(const Key& key, int height) { //以对齐的方式申请内存 //arena是leveldb的内存池,之后会讲到 //原子指针的大小是根据高度来定的 char* mem = arena_->AllocateAligned( sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); //新建一个节点并且返回 return new (mem) Node(key); }
RandomHeight
当要插入一个Node
的时候,它应该在插入在哪些高度上呢?
在levelDB
的实现中,就是使用了生成随机高度的方式。
template<typename Key, class Comparator> int SkipList<Key,Comparator>::RandomHeight() { // Increase height with probability 1 in kBranching static const unsigned int kBranching = 4; int height = 1; //生成随机高度的一个方式 //rnd_是跳表的一个内部成员 while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { height++; } assert(height > 0); assert(height <= kMaxHeight); return height; }
KeyIsAfterNode
字面意思是判断当前Key
值是否在Node
之后,但是这样说似乎有些突兀,其本质就是比较Key
的值和Node
中key
值的大小(因为跳表是有序的)。
template<typename Key, class Comparator> bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const { // null n is considered infinite //使用比较器 return (n != nullptr) && (compare_(n->key, key) < 0); }
一些关于find
的方法
如果对跳表的结构不够熟悉,这部分理解起来可能有些困难,建议画一个跳表,然后结合图片来进行分析(这里提供一个图片)。
//找一个key值比传入参数key大或者相等的Node并返回 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) { //先找到当前节点的next节点 //比较key值和next节点的key值,如果key值大于next节点的key,就说明我们要找的节点在next之后 //反之,就说明我们找到了该高度中我们要找的节点 Node* next = x->Next(level); if (KeyIsAfterNode(key, next)) { // Keep searching in this list //继续搜索当前高度 x = next; } else { //prev用于存放每一层中找到的节点的前一个节点 if (prev != nullptr) prev[level] = x; //如果是最底层,则直接返回 if (level == 0) { return next; } else { // Switch to next list level--; } } } } //找一个比key值比传入参数更小的节点 //如果没有就返回head template<typename Key, class Comparator> typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLessThan(const Key& key) const { Node* x = head_; int level = GetMaxHeight() - 1; while (true) { assert(x == head_ || compare_(x->key, key) < 0); Node* next = x->Next(level); //如果移动到了当前层次尾部或者next->key比传入key值大 if (next == nullptr || compare_(next->key, key) >= 0) { //如果到了最底层则直接返回 if (level == 0) { return x; } else { // Switch to next list //搜索下一个层次 level--; } } else { //继续搜索当前层次 x = next; } } } //找到跳表的尾部 template<typename Key, class Comparator> typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast() const { Node* x = head_; int level = GetMaxHeight() - 1; while (true) { Node* next = x->Next(level); //找到了当前层次的尾部 if (next == nullptr) { //如果是最底层,则直接返回 if (level == 0) { return x; } else { // Switch to next list level--; } } else { x = next; } } }
insert
插入操作是实现中一个非常重要的部分。
void SkipList<Key,Comparator>::Insert(const Key& key) { // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() // here since Insert() is externally synchronized. //指向前一个节点的数组 Node* prev[kMaxHeight]; //调用该函数,并传入参数pre //可以找到插入key值的节点在每一个高度中插入点的前一个位置 Node* x = FindGreaterOrEqual(key, prev); // Our data structure does not allow duplicate insertion assert(x == nullptr || !Equal(key, x->key)); //生成一个随机高度 int height = RandomHeight(); //如果生成的高度大于当前跳表的高度 if (height > GetMaxHeight()) { //初始化高出的部分 for (int i = GetMaxHeight(); i < height; i++) { prev[i] = head_; } //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); // It is ok to mutate max_height_ without any synchronization // with concurrent readers. A concurrent reader that observes // the new value of max_height_ will see either the old value of // new level pointers from head_ (nullptr), or a new value set in // the loop below. In the former case the reader will // immediately drop to the next level since nullptr sorts after all // keys. In the latter case the reader will use the new node. max_height_.NoBarrier_Store(reinterpret_cast<void*>(height)); } //新建一个节点 x = NewNode(key, height); //将该节点插入到之前找到的位置上去 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]. x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); prev[i]->SetNext(i, x); } }
** Contains
**
是否包含key值的Node
template<typename Key, class Comparator> bool SkipList<Key,Comparator>::Contains(const Key& key) const { //调用函数 Node* x = FindGreaterOrEqual(key, nullptr); //如果相等则返回true if (x != nullptr && Equal(key, x->key)) { return true; } else { return false; } }
以上,我们分析了在levelDB
中跳表的具体实现方法,我们可以注意到里面并没有删除操作。 结合跳表的原理和结构来看,这部分也非常好理解。