前言

Skip List是一种随机化的数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间)。基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机化的方式进行的,所以在列表中的查找可以快速的跳过部分列表(因此得名)。所有操作都以对数随机化的时间进行。Skip List可以很好解决有序链表查找特定值的困难。
跳表是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,跳跃表使用概率均衡技术而不是使用强制性均衡,因此,对于插入和删除结点比传统上的平衡树算法更为简洁高效。
一个跳表具有以下特征:
1.一个跳表应该有几个层(level)组成;
2.跳表的第一层包含所有的元素;
3.每一层都是一个有序的链表;
4.如果元素x出现在第i层,则所有比i小的层都包含x;
5.第i层的元素通过一个down指针指向下一层拥有相同值的元素;
6.Top指针指向最高层的第一个元素。
下面来研究一下跳表的核心思想: 先从链表开始,如果是一个简单的链表,那么我们知道在链表中查找一个元素I的话,需要将整个链表遍历一次。
如果是说链表是排序的,并且节点中还存储了指向前面第二个节点的指针的话,那么在查找一个节点时,仅仅需要遍历N/2个节点即可。
如上图所示,是一个即为简单的跳跃表。传统意义的单链表是一个线性结构,向有序的链表中插入一个节点需要O(n)的时间,查找操作需要O(n)的时间。如果我们使用上图的跳跃表,就可以减少查找所需时间为O(n/2),因为我们可以先通过每个节点的最上面的指针先进行查找,这样子就能跳过一半的节点。比如我们想查找19,首先和6比较,大于6之后,在和9进行比较,然后在和12进行比较......最后比较到21的时候,发现21大于19,说明查找的点在17和21之间,从这个过程中,我们可以看出,查找的时候跳过了3、7、12等点,因此查找的复杂度为O(n/2)。
当然上面只是最简单的就是跳跃表,真正的跳表每一个结点不单单只包含指向下一个结点的指针,可能包含很多个指向后续结点的指针,这样就可以跳过一些不必要的结点,从而加快查找、删除等操作。对于一个链表内每一个结点包含多少个指向后续元素的指针,这个过程是通过一个随机函数生成器得到,就是通过随机生成一个结点中指向后续结点的指针数目。
通过上面的跳表的很容易设计这样的数据结构:
定义每个节点类型:
typedef struct nodeStructure *node;
typedef struct nodeStructure
{
keyType key; // key值
valueType value; // value值
// 向前指针数组,根据该节点层数的
// 不同指向不同大小的数组
node forward[1];
};
上面的每个结构体对应着图中的每个节点,如果一个节点是一层的节点的话(如7,12等节点),那么对应的forward将指向一个只含一个元素的数组,以此类推。
定义跳表数据类型:
// 定义跳表数据类型
typedef struct listStructure{
int level;
struct nodeStructure * header;
} * list;
先不看代码先用图来描述一下Skip List构造,插入和删除的过程:
构造Skip List
1、给定一个有序的链表。
2、选择连表中最大和最小的元素,然后从其他元素中按照一定算法(随机)随即选出一些元素,将这些元素组成有序链表。这个新的链表称为一层,原链表称为其下一层。
3、为刚选出的每个元素添加一个指针域,这个指针指向下一层中值同自己相等的元素。Top指针指向该层首元素
4、重复2、3步,直到不再能选择出除最大最小元素以外的元素。
插入过程
例子:插入 119, level = 2
如果 K 大于链表的层数,则要添加新的层。
例子:插入 119, K = 4
删除 21
看到这就很清楚了,上面已经提到所谓的Skip List是每层从它的下一层按照某种规律抽出一些元素,它的操作也很简单,它的操作其实按层来操作链表,基本上是从上往下来操作。
具体的实现如下:
定义数据结构
//
// skiplist_def.h
// test
//
// Created by 杜国超 on 17/9/24.
// Copyright © 2017年 杜国超. All rights reserved.
//
#ifndef skiplist_def_h
#define skiplist_def_h
#define MAX_LEVEL 8
typedef int KeyType;
typedef int ValueType;
//定义节点信息数据结构
template <typename K,typename V>
struct NodeStructure {
K key;
V value;
NodeStructure* forward[1];
};
//定义跳跃表数据结构
template <typename K,typename V>
struct SkipLisStructure{
int level;
NodeStructure<K,V>* header;
};
typedef struct NodeStructure<KeyType,ValueType> NodeType;
typedef struct SkipLisStructure<KeyType,ValueType> ListType;
typedef NodeType* Node;
typedef ListType* List;
#define NEW_LEVEL_NODE(level) (Node)malloc(sizeof(NodeType) + (level) * sizeof(Node))
#endif /* skiplist_def_h */
增删查操作实现
//
// skiplist.h
// test
//
// Created by 杜国超 on 17/9/24.
// Copyright © 2017年 杜国超. All rights reserved.
//
#ifndef skiplist_h
#define skiplist_h
#include "skiplist_def.h"
class CSkipList{
public:
CSkipList();
~CSkipList();
public:
ValueType* Search(const KeyType& key);
bool Insert(KeyType& key,ValueType& value);
bool Delete(const KeyType& key,ValueType& value);
void FreeList();
private:
int RandomLevel();
private:
List _skipList;
int _size;
};
#endif /* skiplist_h */
//
// skiplist.cpp
// test
//
// Created by 杜国超 on 17/9/24.
// Copyright © 2017年 杜国超. All rights reserved.
//
#include "skiplist_def.h"
#include "skiplist.h"
#include <stdlib.h>
CSkipList::CSkipList(){
_skipList = (List)malloc(sizeof(ListType));
// 设置跳表的层level,初始的层为0层(数组从0开始)
_skipList->level = 0;
_skipList->header = NEW_LEVEL_NODE(MAX_LEVEL);
// 将header的forward数组清空
for(int i = 0; i < MAX_LEVEL; ++i)
_skipList->header->forward[i] = NULL;
_size = 0;
}
CSkipList::~CSkipList()
{
FreeList();
}
ValueType* CSkipList::Search(const KeyType& key){
Node node = _skipList->header;
Node indexNode = NULL;
for(int i = _skipList->level - 1; i >= 0; --i){
while((indexNode = node->forward[i]) && (indexNode->forward[i]->key <= key))
{
if (indexNode->key == key)
{
return &(indexNode->value);
}
node = indexNode;
}
}
return NULL;
}
bool CSkipList::Insert(KeyType& key, ValueType& value)
{
Node update[MAX_LEVEL];
int i;
Node node = _skipList->header;
Node indexNode = NULL;
//寻找key所要插入的位置
for(i = _skipList->level - 1; i >= 0; --i){
while((indexNode = node->forward[i]) && (indexNode->forward[i]->key < key))
{
node = indexNode;
}
update[i] = node;
}
node = node->forward[0];
//如果key已经存在
if(node->key == key){
node->value = value;
return false;
}else{
//随机生成新结点的层数
int level = RandomLevel();
if(level > _skipList->level){
for (int i = _skipList->level;i < level;++i)
{
update[i] = _skipList->header;
}
_skipList->level = level;
}
//申请新的结点
Node newNode = NEW_LEVEL_NODE(level);
newNode->key = key;
newNode->value = value;
//调整forward指针
for(int i = level - 1; i >= 0; --i){
node = update[i];
newNode->forward[i] = node->forward[i];
node->forward[i] = newNode;
}
//更新元素数目
++_size;
return true;
}
}
bool CSkipList::Delete(const KeyType& key,ValueType& value){
Node update[MAX_LEVEL];
int i;
Node node = _skipList->header;
Node indexNode = NULL;
//寻找key所要插入的位置
for(i = _skipList->level - 1; i >= 0; --i){
while((indexNode = node->forward[i]) && (indexNode->forward[i]->key < key))
{
node = indexNode;
}
update[i] = node;
}
node = node->forward[0];
//结点不存在
if(node->key != key){
return false;
}else{
value = node->value;
//调整指针
for(i = 0; i < _skipList->level; ++i){
if(update[i]->forward[i] != node)
break;
update[i]->forward[i] = node->forward[i];
}
//删除结点
free(node);
for(int i = _skipList->level - 1; i >= 0; i--){
if(_skipList->header->forward[i]==NULL){
_skipList->level--;
}
}
//更新链表元素数目
--_size;
return true;
}
}
int CSkipList::RandomLevel()
{
int k = 1;
while (rand()%2)
{
k++;
}
k=(k<MAX_LEVEL)?k:MAX_LEVEL;
return k;
}
void CSkipList::FreeList(){
Node p = _skipList->header;
Node q;
while(p != NULL){
q = p->forward[0];
free(p);
p = q;
}
free(p);
free(_skipList);
_size = 0;
}
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
# c
# list
# skip
# skiplist实现排行榜
# c++容器list、vector、map、set区别与用法详解
# python调用c++ ctype list传数组或者返回数组的方法
# C++中list的使用方法及常用list操作总结
# C++中 STL list详解及简单实例
# C++ 关于MFC List Control 控件的总结
# C++模拟实现list功能
# 链表
# 数据结构
# 是一个
# 跳过
# 遍历
# 层数
# 下一层
# 随机化
# 所要
# 的是
# 都是
# 很好
# 是一种
# 第一个
# 就能
# 出现在
# 是从
# 有一定
# 以此类推
# 所需
相关文章:
如何撰写建站申请书?关键要点有哪些?
h5在线制作网站电脑版下载,h5网页制作软件?
建站之星伪静态规则如何正确配置?
美食网站链接制作教程视频,哪个教做美食的网站比较专业点?
在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?
css网站制作参考文献有哪些,易聊怎么注册?
小建面朝正北,A点实际方位是否存在偏差?
SQL查询语句优化的实用方法总结
相册网站制作软件,图片上的网址怎么复制?
大同网页,大同瑞慈医院官网?
建站之星安装失败:服务器环境不兼容?
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
建站之星体验版:智能建站系统+响应式设计,多端适配快速建站
手机怎么制作网站教程步骤,手机怎么做自己的网页链接?
网站制作壁纸教程视频,电脑壁纸网站?
建站主机选虚拟主机还是云服务器更好?
网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
网站制作与设计教程,如何制作一个企业网站,建设网站的基本步骤有哪些?
如何用腾讯建站主机快速创建免费网站?
宝塔面板如何快速创建新站点?
如何快速搭建高效服务器建站系统?
网页设计网站制作软件,microsoft office哪个可以创建网页?
如何快速搭建高效WAP手机网站?
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
如何通过西部数码建站助手快速创建专业网站?
枣阳网站制作,阳新火车站打的到仙岛湖多少钱?
东莞市网站制作公司有哪些,东莞找工作用什么网站好?
网站网页制作电话怎么打,怎样安装和使用钉钉软件免费打电话?
深圳网站制作培训,深圳哪些招聘网站比较好?
公众号网站制作网页,微信公众号怎么制作?
如何用狗爹虚拟主机快速搭建网站?
高端建站如何打造兼具美学与转化的品牌官网?
长沙企业网站制作哪家好,长沙水业集团官方网站?
开心动漫网站制作软件下载,十分开心动画为何停播?
黑客如何利用漏洞与弱口令入侵网站服务器?
如何通过山东自助建站平台快速注册域名?
如何用IIS7快速搭建并优化网站站点?
如何快速搭建响应式可视化网站?
如何选择网络建站服务器?高效建站必看指南
企业微网站怎么做,公司网站和公众号有什么区别?
建站主机助手选型指南:2025年热门推荐与高效部署技巧
个人网站制作流程图片大全,个人网站如何注销?
如何配置IIS站点权限与局域网访问?
如何自定义建站之星网站的导航菜单样式?
音乐网站服务器如何优化API响应速度?
建站VPS推荐:2025年高性能服务器配置指南
网站制作难吗安全吗,做一个网站需要多久时间?
建站为何优先选择香港服务器?
*请认真填写需求信息,我们会在24小时内与您取得联系。