跳躍表簡單的說就是個能夠提供快車道(區間的索引)實現快速訪問的有序鏈表,普通的鏈表的查找複雜度是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;
}