跳跃表简单的说就是个能够提供快车道(区间的索引)实现快速访问的有序链表,普通的链表的查找复杂度是n,这个复杂度太大了,跳跃表查找插入删除都在lg(n)的复杂度,是一种随手就能写出来的数据结构(为什么这么说呢,因为其它lg(n)的可以来实现查找的数据结构实在包含挺多细节的,对我这种渣渣来说每次看完红黑树过不了多久我就会忘了它的操作细节了,只记得它通过维护颜色的平衡来实现树的平衡,更别说随手写了)。关于跳跃表这里就不做介绍了,如果还没了解过这个数据结构的话还是看一遍《算法导论公开课 跳跃表》,才知道跳跃表的理论基础以及推导过程。
代码中有一个容易误解的地方解释一下,randomLevel模拟抛硬币的过程比较不太直观,在插入过程中一个节点上升的次数实际上等价于连续出现“正面”的次数,所以我们直接一次性算出来,而不是每插完一个节点抛一次硬币,这样方便在进行实际插入之前进行一些检查
还有由于插入提升节点的过程中,需要知道往上提升的位置,所以每次往下走的时候都要记住走下来的位置,我们用updateNode记住这个位置,其它的就是普通链表的细节了
本代码没有做边界检查和验证,仅做简单的实现示范使用
//List.h
#include <iostream>
namespace OJP {
template<typename T>
class Node {
public:
Node* next;
Node* down;
T val;
public:
void setNext(Node* next) {
this->next = next;
}
Node(const T& val) {
this->val = val;
this->next = NULL;
}
Node() {
this->next = NULL;
this->down = NULL;
}
};
template<typename T>
class List {
public:
Node<T>* head;
Node<T>* end;
public:
List() {
head = new Node<T>();
end = NULL;
head->next = end;
head->down = NULL;
}
void pushBack(const T& val) {
auto node = new Node<T>(val);
auto tmp = head;
while(tmp->next != end) {
tmp = tmp->next;
}
node->next = end;
tmp->next = node;
}
void insert(Node<T>* node, const T& val) {
auto newNode = new Node<T>(val);
newNode->next = node->next;
node->next = newNode;
}
Node<T>* find(const T& val) {
auto tmp = head->next;
while(tmp != end) {
if(tmp->val == val) {
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
Node<T>* findLastLEOf(const T& t, Node<T>* node = NULL) {
auto tmp = head;
if(node != NULL) {
tmp = node;
if(tmp != head && tmp->val > t) {
return NULL;
}
}
while(tmp->next != end && tmp->next->val <= t) {
tmp = tmp->next;
}
return tmp;
}
Node<T>* findLastLessOf(const T& t, Node<T>* node = NULL) {
auto tmp = head;
if(node != NULL) {
tmp = node;
if(tmp != head && tmp->val >= t) {
return NULL;
}
}
while(tmp->next != end && tmp->next->val < t) {
tmp = tmp->next;
}
return tmp;
}
bool remove(const T& t, Node<T>* after) {
auto tmp = head;
if(after != NULL) {
tmp = after;
}
while(tmp->next != end) {
if(tmp->next->val > t) {
return false;
}
if(tmp->next->val == t) {
Node<T>* delNode = tmp->next;
tmp->next = tmp->next->next;
delete delNode;
return true;
}
}
return false;
}
void for_each(void (*func)(const T& )) {
auto tmp = head->next;
while(tmp != end) {
func(tmp->val);
tmp = tmp->next;
}
}
~List() {
auto tmp = head->next;
while(tmp != end) {
Node<T>* node = tmp;
tmp = tmp->next;
delete node;
}
}
};
}
template<typename T>
void print(const T& a) {
std::cout<<a<<" ";
}
//SkipList.cpp
#include "List.h"
using namespace std;
template<typename T>
class SkipList {
private:
OJP::List<T>* lists;
static const int initialLevel = 64;
int level;
public:
SkipList() {
lists = new OJP::List<T>[initialLevel];
for(int i = 1; i < initialLevel; i++) {
lists[i].head->down = lists[i - 1].head;
}
level = 0;
}
static int randomLevel() {
int i = 0;
while(rand() % 2 == 1) {
i++;
}
return i;
}
bool push(const T& t) {
auto updateNode = new OJP::Node<T>*[initialLevel];
for(int i = 0; i < initialLevel; i++) {
updateNode[i] = lists[i].head;
}
int updateLevel = level;
auto searchFrom = lists[updateLevel].head;
while(updateLevel >= 0) {
OJP::List<T>* list = &lists[updateLevel];
updateNode[updateLevel] = list->findLastLEOf(t, searchFrom);
searchFrom = updateNode[updateLevel]->down;
if(searchFrom != NULL) {
}
updateLevel--;
}
if(updateNode[0]->val == t) {
return false;
} else {
lists[0].insert(updateNode[0], t);
int newLevel = randomLevel();
if(newLevel > initialLevel - 1) {
return false;
} else if(newLevel > level) {
level = newLevel;
}
updateLevel = 0;
while(updateLevel < newLevel) {
++updateLevel;
lists[updateLevel].insert(updateNode[updateLevel], t);
updateNode[updateLevel]->next->down = updateNode[updateLevel - 1]->next;
}
}
return false;
}
bool find(const T& t) {
int searchLevel = level;
auto searchFrom = lists[searchLevel].head;
while(searchLevel >= 0) {
OJP::List<T>* list = &lists[searchLevel];
searchFrom = list->findLastLEOf(t, searchFrom);
if(searchFrom->down && searchLevel > 0) {
searchFrom = searchFrom->down;
}
searchLevel--;
}
if(searchFrom->val == t && searchFrom != lists[0].head) {
return true;
}
return false;
}
bool remove(const T& t) {
int searchLevel = level;
auto searchFrom = lists[searchLevel].head;
while(searchLevel >= 0) {
OJP::List<T>* list = &lists[searchLevel];
searchFrom = list->findLastLessOf(t, searchFrom);
list->remove(t, searchFrom);
if(searchFrom->down && searchLevel > 0) {
searchFrom = searchFrom->down;
}
searchLevel--;
}
if(searchFrom->val == t && searchFrom != lists[0].head) {
return true;
}
return false;
}
~SkipList() {
delete []lists;
}
void dump() {
for(int i = level; i >= 0; i--) {
cout<<"level["<<i<<"]: ";
lists[i].for_each(print);
cout<<endl;
}
}
};
int main() {
SkipList<int> skipList = SkipList<int>();
for(int i = 0; i < 100000; i++) {
int val = rand() % 100000;
cout<<"push "<<val<<endl;
skipList.push(val);
}
for(int i = 0; i < 100000; i++) {
int val = rand() % 100000;
cout<<"find "<<val<<" "<<skipList.find(val)<<endl;
}
/*
skipList.dump();
skipList.remove(79);
skipList.remove(92);
skipList.remove(99);
skipList.dump();*/
return 0;
}