一、简介
跳表实际上是对链表进行改造,以支持类似于二分搜索的算法;
内部包含n个元素,其查询和插入的平均时间复杂度为O(logN);
其结果简单,为多级单链表,使用空间来换取时间(需要额外将近一倍空间),甚至可以用来替代红黑树(redis中的有序集合);
【查询】:首先,在最上层(最稀疏)开始查找,不断跳转到下一个层次,直到找到元素;
1、如何生成跳表
通过类似二分的思想对其进行生成多级索引,查询即可根据前后的区间来锁定;
跳表的高度:log(2)n-1;
跳表消耗的空间这么大,值得嘛???
以下看到需要用到的额外空间将近多出一倍,但在实际的开发过程中,索引节点将记录关键值和指针,不需要存储对象,以此来减
少对空间的损耗;
插入数据
首先查找到该位置,在往内部插入数据;
在插入数据中为了避免后续造成某个区间的索引个数过多,我们需要为此进行维护;
- 让随机的方式来决定新插入节点来决定索引的层数;
删除数据
将原始链表中删除以及索引删除即可;
2、代码
/** 链表节点 */
template<class T>
struct Node {
T data = -1;
vector<Node*> forward;
int maxLevel;
Node() { forward.resize(16); }
Node(T val, int level) : data(val), maxLevel(level) { forward.resize(16); }
string toString() {
stringstream ss;
ss << "{ data: " << data
<< "; levels: " << maxLevel
<< " }";
return ss.str();
}
};
template<class T>
class SkipList {
public:
SkipList() {}
SkipList(Node<T> *node) : head(node) {
srand(time(0));
}
~SkipList() {}
/** 查找函数 */
Node<T>* find(int val) {
Node<T>* p = head;
/* 从最上层开始查找 */
for (int i = levelCnt - 1; i >= 0 ; --i) {
while (p->forward[i] != nullptr && p->forward[i]->data < val ) {
p = p->forward[i];
}
}
auto tmp = p->forward[0];
if(tmp != nullptr && tmp->data == val) {
return tmp;
}else {
return nullptr;
}
}
/** 插入函数 */
void insert(int val) {
int level = randomLevel();
Node<T>* newNode = new Node<T>(val, level);
vector<Node<T>*> update;
update.resize(level);
for (int i = 0; i < level; ++i) {
update[i] = head;
}
Node<T> *p = head;
for(int i= level - 1; i>=0; --i) {
while (p->forward[i] != nullptr && p->forward[i]->data < val) {
p = p->forward[i];
}
update[i] = p;
}
for(int i=0; i<level; ++i) {
newNode->forward[i] = update[i]->forward[i];
update[i]->forward[i] = newNode;
}
if(levelCnt < level) levelCnt = level;
}
/** 删除函数 */
void erase(int val) {
vector<Node<T>*> update;
update.resize(levelCnt);
Node<T>* p = head;
for(int i=levelCnt - 1; i>=0; --i) {
while (p->forward[i] != nullptr && p->forward[i]->data < val) {
p = p->forward[i];
}
update[i] = p;
}
if(p->forward[0] != nullptr && p->forward[0]->data == val) {
for(int i=levelCnt-1; i>=0; --i) {
if(update[i]->forward[i] != nullptr && update[i]->forward[i]->data == val) {
update[i]->forward[i] = update[i]->forward[i]->forward[i];
}
}
}
while (levelCnt > 1 && head->forward[levelCnt] == nullptr) {
levelCnt--;
}
}
/**
* 设置等概率返回层数
* */
int randomLevel() {
int level = 1;
while ((rand() & 0xFFFF) < (0.25 * 0xFFFF)) {
++level;
}
return min(level, MAX_LEVEL);
}
/** 打印函数 */
void myPrint() {
for(int i=0; i<head->maxLevel; ++i) {
Node<int> *tmp = head;
cout << "this level: " << i << endl;
while (tmp->forward[i] != nullptr) {
cout << tmp->forward[i]->data << " ";
tmp = tmp->forward[i];
}
cout << endl;
}
}
private:
static float SKIPLIST_P;
static int MAX_LEVEL;
int levelCnt = 4;
Node<T>* head;
};
template<class T>
float SkipList<T>::SKIPLIST_P = 0.25;
template<class T>
int SkipList<T>::MAX_LEVEL = 16;
void test_func(){
Node<int> node(1, 6);
SkipList<int> sl(&node);
for(int i=0;i<101; ++i)
sl.insert(i);
sl.myPrint();
auto tmp = sl.find(29);
cout << tmp->toString() << endl;
sl.erase(29);
sl.myPrint();
}
int main() {
test_func();
return 0;
}