跳表 (Skip List) C++ 实现

本文介绍了跳表的基本原理和C++实现,跳表是一种动态构建的多层索引数据结构,提供O(logn)的插入、删除和搜索操作。文章详细讲述了如何创建SkipNode、SkipList,以及随机层数、节点最大层数的确定,还包括基本操作的实现和主函数的展示。
摘要由CSDN通过智能技术生成

在学习 C++ 中的过程中,找个算法作为练习。
仅供参考。

跳表原理

跳表原理讲解请参考 https://lotabout.me/2018/skip-list/
为了节约时间,这里只是简单说明,原文如上。

跳表(skip list) 对标的是平衡树(AVL Tree),是一种 插入/删除/搜索 都是 O ( l o g n ) O(log n) O(logn) 的数据结构。它最大的优势是原理简单、容易实现、方便扩展、效率更高。因此在一些热门的项目里用来替代平衡树,如 redis, leveldb 等。

跳表顾名思义就是跳跃的表格,理解起来其实就是跳着插入或者搜索。具体什么意思呢,其实就像是二分搜索一样,每次都将数组分成两点分,先定位搜索或者插入的数据在哪一部分,就可以节约搜索的时间。跳表其实是一样的原理,即建立多层索引(多层链表)。如果每次都是以二等分来建立索引的话,即如下图所示:
在这里插入图片描述
但是上述结构是“静态”的,即我们先拥有了一个链表,再在之上建了多层的索引。但是在实际使用中,我们的链表是通过多次插入/删除形成的,换句话说是“动态”的。上述的结构要求上层相邻节点与对应下层节点间的个数比是 1:2,随意插入/删除一个节点,这个要求就被被破坏了。

因此跳表(skip list)表示,我们就不强制要求 1:2 了,一个节点要不要被索引,建几层的索引,都在节点插入时由抛硬币决定。当然,虽然索引的节点、索引的层数是随机的,为了保证搜索的效率,要大致保证每层的节点数目与上节的结构相当。下面是一个随机生成的跳表:

在这里插入图片描述
对于上述随机跳表而言,每次插入一个新结点的时候,该结点的索引层数是抛硬币决定的,即由随机算法决定的。

当然为了防止运气太好,层数太高,我们一般会设置一个最大的层数 M a x L e v e l MaxLevel MaxLevel. 一般 M a x L e v e l = l o g 1 / p n MaxLevel=log_{1/p}n MaxLevel=log1/pn p p p 为概率。

跳表 c++ 实现

思路:

  1. 首先创建一个结点的结构体,结构体里包含 一个键值对,key 用来建立索引,而 value 则用于存储真正的值;指向下一个结点的指针 next,以及标志每个结点索引层数的参数 level. next 指针是一个数组,用于存储结点在所有层数上的下一个结点。 例如, 上述图中结点6的next指针为{NIL, 25, 9, 7}.
  2. 创建class skipList, 包含头结点,尾结点,list 的最大层数,随机层数方法,以及一些列操作。
  3. 头结点和尾节点分别为整型的最小值和最大值,并在初始化时让所有层数上的头结点都指向尾节点。
  4. 操作包含插入,查找,删除。

SkipNode

为了可以适用于任何类型的value, 这里用了 template

template<typename T>
struct SkipNode
{
   
	int key;
	T value;
	vector<SkipNode*> next;

	SkipNode(int k, T v, int level);
};
//构造函数,初始化
template<typename T> SkipNode<T>::SkipNode(int k, T v, int level) 
	: key(k), value(v)
{
   
	for (int i = 0; i < level; i++)
	{
   
		next.push_back(nullptr);
	}
}

SkipList

template<class T>
class SkipList
{
   

public:
	//头结点
	SkipNode<T>* head;
	
	//列表最大层数
	int maxLevel;

	//整型的最小值和最大值
	const int minInt = numeric_limits<int>::min();
	const int maxInt = numeric_limits<int>::max();

public:
	//构造函数
	SkipList(int maxLevel, T iniValue);

	//析构函数
	~SkipList();

	//随机层数方法
	int randomLevel();

	//插入, 查找, 删除
	SkipNode<T>* insert(int k, T v);
	SkipNode<T>* find(int k);
	SkipNode<T>* deleteNode(int k);

	//打印
	void printNode();

private:

	//尾节点
	SkipNode<T>* tail;
	
	//找到当前列表或者node的最大层数
	int nodeLevel(vector<SkipNode<T>*> p);
};

//初始化
template<class T> SkipList<T>::SkipList(int maxLevel, T iniValue)
	: maxLevel(maxLevel)
{
   
	//初始化头结点和尾节点为整型最小值和最大值
	head = 
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值