- 对单链表查找一个元素的时间复杂度是 O(n)
- 通过对链表建立多级索引的结构,就是跳表,查找任意数据、插入数据、删除数据的时间复杂度均为 O(log n)
- 前提:建立了索引,用空间换时间的思路
- (每两个节点建立一个索引)索引节点总和 n/2+n/4+n/8+…+8+4+2 = n-2,空间复杂度 O(n)
- 插入和删除后,动态更新索引,避免局部链表元素过多或者过少,退化成单链表
skiplist.h
/*** @description: 跳表* @author: michael ming* @date: 2019/4/22 22:21* @modified by: */#ifndef SKIPLIST_SKIPLIST_H
#define SKIPLIST_SKIPLIST_H
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
typedef unsigned int UINT;
template <class T>
class skipNode
{
public:T data;skipNode<T> **next; //跳表节点的next是 skipNode<T>* 类型的数组skipNode(const UINT level){next = new skipNode<T>* [level+1]; //索引级别从0(链表自身)开始for(int i = 0; i < level+1; ++i)next[i] = NULL;}skipNode(const UINT level, const T& inputdata):data(inputdata){next = new skipNode<T>* [level+1]; //索引级别从0(链表自身)开始for(int i = 0; i < level+1; ++i)next[i] = NULL;}~skipNode<T>(){delete [] next;}
};
template <class T>
class skiplist
{
private:UINT randomLevel(){
// static bool flag = false;
// if(!flag)
// {
// srand(UINT(time(0)));
// flag = true;
// }
// else
// flag = false;UINT lv = 0;for(int i = 0; i < maxLevel; ++i){if(rand()%2)lv++;}return lv;}
public:UINT maxLevel;skipNode<T> *head;skiplist<T>(UINT level = 10):maxLevel(level){head = new skipNode<T>(level);}~skiplist<T>(){skipNode<T> *p = head, *q;while(p){q = p;p = p->next[0];delete q;}}void insert(const T& inputdata){skipNode<T>* newNode = new skipNode<T>(maxLevel, inputdata);skipNode<T>* temPos[maxLevel+1];skipNode<T> *p = head, *q = NULL;for(int i = maxLevel; i >= 0; i--) //记录插入点在每层的前一个位置{while((q = p->next[i]) && (q->data <= inputdata)){p = q;}temPos[i] = p;}UINT lv = randomLevel(); //新节点的随机索引级数for(int i = 0; i <= lv; ++i) //将新节点依次连接进去{newNode->next[i] = temPos[i]->next[i];temPos[i]->next[i] = newNode;}}void delete_node(const T& inputdata){skipNode<T>* temPos[maxLevel+1];skipNode<T> *p = head, *q = NULL;for(int i = maxLevel; i >= 0; i--){while((q = p->next[i]) && (q->data < inputdata)){p = q;}temPos[i] = p;}if(q && q->data == inputdata){for(int i = 0; i <= maxLevel; ++i){if(temPos[i]->next[i] == q)temPos[i]->next[i] = q->next[i];}delete q;q = NULL;}}void printSkipList(){skipNode<T> *p, *q;for(int i = maxLevel; i >= 0; --i){p = head;while(q = p->next[i]){cout << q->data << " -> ";p = q;}cout << endl;}}
};#endif //SKIPLIST_SKIPLIST_H
test_skiplist.cpp
/*** @description: 测试跳表* @author: michael ming* @date: 2019/4/23 0:07* @modified by: */
#include "skiplist.h"
int main()
{skiplist<int> intSList;for(int i = 0; i < 10; ++i){intSList.insert(i);}intSList.printSkipList();intSList.delete_node(9);intSList.printSkipList();intSList.delete_node(100);intSList.printSkipList();return 0;
}
以上写的比较简单,删除多个节点后,索引重新合理重建没有写。应该还有很多需要改进的地方,先放一放,往后继续学,保持学习进度。
测试结果: