Feel skiplist as long as the height is clear. The following is a function of the randomly generated height randomheight ()
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;
while (Height < kmaxheight && (rnd_. Next ()% kbranching) = = 0) {
height++;
}
ASSERT (height > 0);
ASSERT (height <= kmaxheight);
return height;
}
Insert operation:
Template<typename Key, class comparator> void Skiplist<key,comparator>::insert (const key& Key) {//TODO (opt): We can use a barrier-free (shielded, barrier/barrier-free) variant of findgreaterorequal ()//here since Insert () is externally sy
Nchronized.
Prev for each layer of the front node node* prev[kmaxheight];
Find the inserted node node* x = Findgreaterorequal (key, prev); Our data structure does isn't allow duplicate insertion assert (x = = NULL | |!
Equal (key, X->key));
Randomly generated node height 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 a synchronization//with concurrent readers. A concurrent reader that observes//the new value of Max_height_ would see either the old value of//new level PO Inters from Head_ (NULL), or a new value set in//the loop below. In THe former case the reader would//immediately drop to the next level since NULL sorts after all//keys.
The latter case the reader would use the new node. Sets the maximum height max_height_.
Nobarrier_store (reinterpret_cast<void*> (height));
}//Generate a new node x = NewNode (key, height); for (int i = 0; i < height; i++) {//Nobarrier_setnext () suffices since we'll add a barrier when//we publi
SH A pointer to "X" in Prev[i].
X->nobarrier_setnext (i, Prev[i]->nobarrier_next (i));
Prev[i]->setnext (i, x); }
}
Find an operation:
Template<typename Key, class comparator>
TypeName skiplist<key,comparator>::node* Skiplist<key, Comparator>::findgreaterorequal (const key& Key, node** prev)
const {
node* x = head_;
Find
int level = Getmaxheight ()-1
, starting at the top while (true) {
node* next = X->next (level);
Look to the right
if (Keyisafternode (key, Next)) {
//Keep searching in this list
x = next;
} else {
//down lookup
if (prev! = NULL) Prev[level] = x;
if (level = = 0) {
return next;
} else {
//Switch to Next list
level--;}
}}}
Whole SkipList.h Source:
Copyright (c) the LevelDB Authors.
All rights reserved. Use of this source code was governed by a Bsd-style license, can be//found in the license file.
See the AUTHORS file for names of contributors.
Thread Safety//-------------////writes require external synchronization, most likely a mutex. Reads require a guarantee that the skiplist would not being destroyed//while the read was in progress.
Apart from this, reads progress//without any internal locking or synchronization. Invariants:////(1) allocated nodes is never deleted until the skiplist is//destroyed.
This is trivially guaranteed by the code since we//never delete any skip list nodes. (2) The contents of a node except for the Next/prev pointers is//immutable after the node have been linked into th
E skiplist. Only Insert () modifies the list, and it's careful to initialize//a node and use Release-stores to publish the nodes
In one or/+ more lists. ... prev vs. nextPointer ordering #include <assert.h> #include <stdlib.h> #include "port/port.h" #include "util/arena.h" # Include "Util/random.h"/** * skiplist apply probabilities to ensure balance, balanced tree with strict rotation to ensure balance * Use skiplist Yes find specific time complexity is O (Logn), with the balance tree has the same complexity, save space,
Average 1.33 pointers per inspection * Leveldb The highest number of layers is 12, only inserts and modifications are allowed, the record key is not allowed to repeat, add a sequene Num * Specification: Parameters use a reference, the return value uses the pointer * */namespace Leveldb {
Class Arena;
Template<typename Key, Class comparator> class Skiplist {private:struct Node; Public://Create A new Skiplist object that would use "CMP" for comparing keys,//and would allocate memory using "*ar Ena ".
Objects allocated in the arena//must remain allocated for the lifetime of the Skiplist object.
Explicit Skiplist (Comparator cmp, arena* Arena);
Insert key into the list.
Requires:nothing that compares equal to key are currently in the list.
void Insert (const key& Key);
Returns true iff an entry, compares equal to key are in the list. BOOL Contains (const key& Key) Const Iteration over the contents of a skip list class Iterator {public://Initialize an Iterator over the Specifi
Ed 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 was Valid () IFF list is not empty.
void Seektofirst ();
Position at the last entry in list.
Final state of Iterator was Valid () IFF list is not empty.
void Seektolast ();
Private:const skiplist* List_; node* Node_;
Intentionally copyable};
The highest level of the hop table Private:enum {kmaxheight = 12};
Immutable (immutable) after construction Comparator const compare_; Stage, arena, place (memory pool only for application space) arena* const Arena_;
Arena used for allocations of nodes node* Const HEAD_; Modified only by Insert ().
Read racily by readers, but stale//values is OK. Port::atomicpointer Max_height_; Height of the entire list inline int getmaxheight () const {return static_cast<int> (reinterpret_c Ast<intptr_t> (Max_height_.
Nobarrier_load ()));
}//Read/written only by Insert ().
Random Rnd_;
node* NewNode (const key& Key, int height);
int Randomheight ();
BOOL Equal (const key& A, const key& b) Const {return (Compare_ (A, b) = = 0);}
Return true if key is greater than the data stored in "n" bool Keyisafternode (const key& key, node* N) const;
Return The earliest node that is comes at or after key. Return NULL If there is no such node. If prev is non-null, fills Prev[level] with pointer to previous//node at "level" for every level in [0..max_he
IGHT_-1].
node* findgreaterorequal (const key& Key, node** prev) const;
Return the latest node with a key < key.
Return Head_ If there is no such node.
node* Findlessthan (const key& Key) const;
Return the last node in the list.
Return Head_ if list is empty.
node* FindLast () const;
No copying allowed skiplist (const skiplist&);
void operator= (const skiplist&);
}; Implementation details follow Template<typename Key, class comparator> struct skiplist<key,comparator>::
Node {explicit node (const key& K): Key (k) {} Key const key; Accessors/mutators for links.
Wrapped in methods so we can//add the appropriate barriers as necessary.
node* Next (int n) {assert (n >= 0); Use the ' acquire load ' so that we observe a fully initialized//VErsion of the returned Node. Return reinterpret_cast<node*> (Next_[n].
Acquire_load ());
} void Setnext (int n, node* x) {assert (n >= 0); Use a ' release store ' So, anybody who reads through this//pointer observes a fully initialized version of the
Inserted node. Next_[n].
Release_store (x);
}//No-barrier variants that can is safely used in a few locations.
node* Nobarrier_next (int n) {assert (n >= 0); Return reinterpret_cast<node*> (Next_[n].
Nobarrier_load ());
} void Nobarrier_setnext (int n, node* x) {assert (n >= 0); Next_[n].
Nobarrier_store (x); } private://Array of length equal to the node height.
NEXT_[0] is lowest level link.
Port::atomicpointer Next_[1];
}; Template<typename Key, Class Comparator> TypeName skiplist<key,comparator>::node* Skiplist<key, Comparator>::newnode (const key& Key, int height) {char* mem = arena_->allocatealigned (sizeof (Node) + s) Izeof (PORt::atomicpointer) * (height-1));
return new (MEM) Node (key); } template<typename Key, class comparator> inline Skiplist<key,comparator>::iterator::iterator (const
skiplist* list) {list_ = list;
Node_ = NULL;
} template<typename Key, class comparator>, inline bool Skiplist<key,comparator>::iterator::valid () const {
return node_! = NULL; } template<typename Key, class comparator>, inline const key& Skiplist<key,comparator>::iterator::key ()
const {ASSERT (Valid ());
Return node_->key; } template<typename Key, class comparator>, inline void Skiplist<key,comparator>::iterator::next () {ASSERT (
Valid ());
Node_ = Node_->next (0); } template<typename Key, class comparator>, inline void Skiplist<key,comparator>::iterator::P rev () {//Inst
EAD of using explicit "prev" links, we just search for the//last node that falls before key.
ASSERT (Valid ());
Node_ = List_->findlessthan (Node_->key); if (nOde_ = = List_->head_) {node_ = NULL; }} Template<typename key, class comparator> inline void Skiplist<key,comparator>::iterator::seek (const key
& target) {Node_ = List_->findgreaterorequal (target, NULL);}
Template<typename Key, class comparator>, inline void Skiplist<key,comparator>::iterator::seektofirst () {
Node_ = List_->head_->next (0); } template<typename Key, class comparator>, inline void Skiplist<key,comparator>::iterator::seektolast () {n
Ode_ = List_->findlast ();
if (Node_ = = list_->head_) {node_ = NULL; }} template<typename Key, class comparator> int skiplist<key,comparator>::randomheight () {//Increase Hei
Ght with probability 1 in kbranching static const unsigned int kbranching = 4;
int height = 1; while (Height < kmaxheight && (rnd_.
Next ()% kbranching) = = 0) {height++;
} assert (height > 0);
ASSERT (height <= kmaxheight);
return height;
}Template<typename key, Class comparator> bool Skiplist<key,comparator>::keyisafternode (const Key& Key
, node* N) const {//null n is considered infinite return (n! = NULL) && (Compare_ (N->key, key) < 0);} /** * Find, from left to right, find from top to bottom */template<typename Key, Class Comparator> TypeName skiplist<key,comparator>::node* S
Kiplist<key,comparator>::findgreaterorequal (const key& Key, node** prev) const {node* x = Head_;
find int level = Getmaxheight ()-1, starting at the top
while (true) {node* next = X->next (level);
Look to the right if (Keyisafternode (key, Next)) {//Keep searching in this list x = Next;
} else {//Look down if (prev! = NULL) Prev[level] = x;
if (level = = 0) {return next;
} else {//Switch to next list level--; }}}} Template<typename Key, class Comparator> TypeName skiplist<key,comparator>::node* skiplist<k Ey,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);
if (next = NULL | | 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,com
Parator>::findlast () const {node* x = Head_;
int level = Getmaxheight ()-1;
while (true) {node* next = X->next (level);
if (next = = NULL) {if (level = = 0) {return x;
} else {//Switch to next list level--;
}} else {x = next; }}}/** * skiplist initialization * */Template<typename Key, class comparator> skiplist<key,comparator>::skiplist (
Comparator CMP, arena* Arena) : Compare_ (CMP), Arena_ (Arena), Head_ (NewNode (0 */any key would do */, Kmaxheight)), Max_height_ (reint Erpret_cast<void*> (1)), Rnd_ (0xdeadbeef) {for (int i = 0; i < kmaxheight; i++) {Head_->setnext (i
, NULL); }}/** * Insert a new Key * */template<typename key, class comparator> void Skiplist<key,comparator>::insert (con St key& Key) {//TODO (OPT): We can use a barrier-free (shield, barrier/barrier-free) variant of findgreaterorequal ()//Here Sin
Ce Insert () is externally synchronized.
Prev for each layer of the front node node* prev[kmaxheight];
Find the inserted node node* x = Findgreaterorequal (key, prev); Our data structure does isn't allow duplicate insertion assert (x = = NULL | |!
Equal (key, X->key));
Randomly generated node height 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 a synchronization//with concurrent readers. A concurrent reader that observes//the new value of Max_height_ would see either the old value of//new level PO Inters from Head_ (NULL), or a new value set in//the loop below. In the former case the reader would//immediately drop to the next level since NULL sorts after all//keys.
The latter case the reader would use the new node. Sets the maximum height max_height_.
Nobarrier_store (reinterpret_cast<void*> (height));
}//Generate a new node x = NewNode (key, height); for (int i = 0; i < height; i++) {//Nobarrier_setnext () suffices since we'll add a barrier when//we publi
SH A pointer to "X" in Prev[i].
X->nobarrier_setnext (i, Prev[i]->nobarrier_next (i));
Prev[i]->setnext (i, x); }}/** * includes */Template<typename Key, class comparator> bool Skiplist<key,comparator>::contains (const KEY&A mp Key) const {node* x = findgreateroreqUAL (key, NULL);
if (x! = NULL && Equal (Key, X->key)) {return true;
} else {return false;
}}}//Namespace Leveldb