首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2020-11-12 跳表

2020-11-12 跳表

作者头像
用户7719114
发布于 2022-02-22 05:30:13
发布于 2022-02-22 05:30:13
20200
代码可运行
举报
文章被收录于专栏:C++小白C++小白
运行总次数:0
代码可运行

文章目录

前言

用c++实现一个简单跳表。

一、什么是跳表

跳表的介绍很多数据结构中都有,第一次了解的推荐看一下这片博客:https://blog.csdn.net/daniel_ustc/article/details/20218489 ,在这里就不介绍了

二、c++实现代码

代码如下(示例):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <limits.h>
#include <vector>
#include <iostream>
using namespace std;

struct SKNode
{
	int key;
	int value;
	int level;
	SKNode **next;
	SKNode(int iKey, int iValue, int iLevel) :key(iKey), value(iValue), level(iLevel)
	{
		next = new SKNode *[iLevel];
	}
	void print()
	{
		std::cout << "--------------" << std::endl;
		std::cout << "key = " << key << ", value = " << value << std::endl;
		std::cout << "--------------" << std::endl;
	}
};

class SkipList
{
public:
	SkipList(double iProb, int iMaxLevel);
	~SkipList();
	SKNode *find(int iKey);
	void insert(int iKey, int iValue);
	void erase(int iKey);
	void print();
private:
	int getLevel();
	SKNode *search(int iKey,vector<SKNode *>&ovNodes);
private:
	int m_curLevel;         //当前最大层数
	const int m_maxLevel;   //跳表最大层数
	double m_probability;   //生成下一层的概率
	SKNode *m_pHeadNode;    //跳表头结点,头结点的key最小
	SKNode *m_pTailNode;    //跳表尾部结点,尾结点的key最大
};

SkipList::SkipList(double iProb=0.5, int iMaxLevel=10)
	:m_probability(iProb), m_maxLevel(iMaxLevel), m_curLevel(0)
{
	m_pHeadNode = new SKNode(INT_MIN, 0, m_maxLevel);
	m_pTailNode = new SKNode(INT_MAX, 0, m_maxLevel);
	//将头尾结点连结起来
	for (int i = 0; i < m_maxLevel;++i)
	{
		m_pHeadNode->next[i] = m_pTailNode;
	}
}

SkipList::~SkipList()
{
	SKNode *pNext = nullptr;
	while (m_pHeadNode!=m_pTailNode)
	{
		pNext = m_pHeadNode->next[0];
		delete m_pHeadNode;
		m_pHeadNode = pNext;
	}
	delete m_pTailNode;
}

int SkipList::getLevel()
{
	int iCutNum = 1000 * m_probability;
	int iRandNum = rand() % 1001;
	int iLevel = 1;
	while (iRandNum<=iCutNum)
	{
		iLevel++;
		iRandNum = rand() % 1001;
	}
	return iLevel;
}

SKNode *SkipList::search(int iKey, vector<SKNode *>&ovNodes)
{
	//逐层从上向下查找,直到找到第一个不小于指定key的节点
	ovNodes.resize(m_curLevel);
	SKNode *node = m_pHeadNode;
	for (int i = m_curLevel-1; i >= 0; --i)
	{
		
		while (node->next[i]->key < iKey)
		{
			int temp = node->next[i]->key;
			node = node->next[i];
		}
		ovNodes[i]=node;
	}
	return node->next[0];
}

SKNode *SkipList::find(int iKey)
{
	//逐层从上向下查找,直到找到第一个不小于指定key的节点
	vector<SKNode *>vNodes;
	SKNode *node = search(iKey, vNodes);
	if (node->key == iKey)
	{
		return node;
	}
	return nullptr;
}

void SkipList::insert(int iKey, int iValue)
{
	vector<SKNode *>vNodes;
	SKNode *node = search(iKey, vNodes);
	if (node->key == iKey)
	{
		node->value=iValue;
		return;
	}
	int iLevel = getLevel();
	SKNode *pNewNode = new SKNode(iKey, iValue, iLevel);
	if (iLevel>m_maxLevel)
	{
		iLevel = m_maxLevel;
	}
	if (iLevel>m_curLevel)
	{
		for (int i = m_curLevel; i < iLevel;++i)
		{
			vNodes.push_back(m_pHeadNode);
		}
		m_curLevel = iLevel;
	}
	for (int i = 0; i < iLevel; ++i)
	{
		pNewNode->next[i] = vNodes[i]->next[i];
		vNodes[i]->next[i] = pNewNode;
	}
}

void SkipList::erase(int iKey)
{
	vector<SKNode *>vNodes;
	SKNode *node = search(iKey, vNodes);
	if (node->key != iKey)
	{
		return;
	}
	for (int i = 0; i < m_curLevel&&vNodes[i]->next[i]==node; ++i)
	{
		vNodes[i]->next[i] = node->next[i];
	}
	while (m_curLevel>=0&&m_pHeadNode->next[m_curLevel]==m_pTailNode)
	{
		--m_curLevel;
	}
	delete node;
}

void SkipList::print()
{
	cout << "output all node->" << endl;
	SKNode* node, *nextNode;
	for (int i = m_curLevel-1; i >= 0; i--)
	{
		node = m_pHeadNode->next[0];
		cout << "第" << i+1 << "层" << "->";
		while (node != m_pTailNode) {
			cout << "(k=" << node->key << " , v=" << node->value << ")";
			if (node->next[0]!=m_pTailNode)
			{
				cout << " -> ";
			}
			node = node->next[i];
		}
		cout << endl;
	}
	cout << "--------------" << endl;
}

int main()
{
	SkipList list;
	list.insert(1, 100);
	list.insert(3, 300);
	list.insert(2, 200);
	list.insert(7, 700);
	list.insert(6, 600);
	list.insert(4, 400);
	list.insert(5, 500);
	list.print();

	SKNode* node = list.find(3);
	if (node)
		node->print();
	else
		cout << "find node not exist" << endl;

	list.erase(3);
	list.print();

	node = list.find(3);
	if (node)
		node->print();
	else
		cout << "find node not exist" << endl;
	system("pause");
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
data_structure_and_algorithm -- 跳表:python & java & c-cpp 实现
版权声明:本文为博主原创文章,未经博主允许不得转载。有问题可以加微信:lp9628(注明CSDN)。 https://blog.csdn.net/u014365862/article/details/84311162
MachineLP
2019/05/26
8850
跳表 - skipList
SkipList(跳表)这种数据结构是由William Pugh于1990年在在 Communications of the ACM June 1990, 33(6) 668-676 发表了Skip lists: a probabilistic alternative to balanced trees,在其中详细描述了他的工作。由论文标题可知,SkipList的设计初衷是作为替换平衡树的一种选择。
夹胡碰
2020/08/27
5490
数据结构(9)-- 跳表
让你现场手写一棵红黑树、AVL树、伸展树之类的,你行吗? 要不让我查资料,我估计只能扯皮。
看、未来
2021/09/18
3790
数据结构学习——skiplist跳表
Skiplist是一个用于有序元素序列快速搜索的数据结构,由美国计算机科学家William Pugh发明于1989年。他在论文《Skip lists: a probabilistic alternative to balanced trees》中详细介绍了跳表的数据结构和插入删除等操作。论文是这么介绍跳表的:
全栈程序员站长
2022/11/01
1.5K0
数据结构学习——skiplist跳表
跳表原理及C++实现
二分查找底层依赖的是数组随机访问的特性,所以只能用数组来实现。如果数据存储在链表中,就真的没法用二分查找算法了吗?实际上,只需要对链表稍加改造,就可以支持类似“二分”的查找算法。改造之后的数据结构叫作跳表。
evenleo
2020/08/21
1.4K0
跳表原理及C++实现
漫画:什么是 “跳表” ?
如果数组的长度是n,二分查找的时间复杂度是O(logn),比起从左到右逐个遍历元素进行查找的方式,大大提升了查找性能。
小灰
2020/08/27
7781
数据结构:跳跃链表
开发时经常使用的平衡数据结构有B数、红黑数,AVL数。但是如果让你实现其中一种,很难,实现起来费时间。而跳跃链表一种基于链表数组实现的快速查找数据结构,目前开源软件 Redis 和 LevelDB 都有用到它。它的效率和红黑树以及 AVL 树不相上下
呆呆
2021/08/01
2310
【数据结构】跳表SkipList代码解析(C++)
跳表SkipList解析 原项目链接——基于跳表实现的轻量级键值数据库 添加注释后——SkipList 什么是跳表 这里不做介绍,详见: 跳表──没听过但很犀利的数据结构 拜托,面试别再问我跳表了! 代码解析 主要理解点 先来张图 各个节点是如何相连接(关联)的? 通过每个节点的forward数组,forward数组存储当前节点,在每一层的下一个节点。 以头节点为例,头结点的forward存储的是每一层的第一个节点。然后通过第一个节点的forward[level],拿到该层的后面元
半生瓜的blog
2023/05/13
3630
【数据结构】跳表SkipList代码解析(C++)
面试官:为何Redis使用跳表而非红黑树实现SortedSet?
知道跳表(Skip List)是在看关于Redis的书的时候,Redis中的有序集合使用了跳表数据结构。接着就查了一些博客,来学习一下跳表。后面会使用Java代码来简单实现跳表。
JavaEdge
2021/12/07
6220
面试官:为何Redis使用跳表而非红黑树实现SortedSet?
数据结构--跳表SkipList
以上写的比较简单,删除多个节点后,索引重新合理重建没有写。应该还有很多需要改进的地方,先放一放,往后继续学,保持学习进度。 测试结果:
Michael阿明
2021/02/20
3040
数据结构--跳表SkipList
跳表很难吗?手把手教你如何跳跃它!
​ skiplist是一种随机化的数据结构,基于并联的链表,实现简单,插入、删除、查找的复杂度均为 O(logN)(大多数情况下,因为是实现上是概率问题),因为其性能匹敌红黑树且实现较为简单,因此在很多著名项目都用 skiplist 来代替红黑树,例如 LevelDB、RocksDB、Redis中的有序集合zset 的底层存储结构就是用的skiplist。
利刃大大
2023/10/17
7840
跳表很难吗?手把手教你如何跳跃它!
list类
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
海盗船长
2020/08/27
1K0
手写了个可能是Github性能最强的Go跳表
作者:phongchen,腾讯 IEG 后台开发工程师 2022 年 3 月,广大人民期盼已久的支持的泛型的 go1.18 发布了。但是目前基于泛型的容器实现还不多。我实现了一套类似 C++中 STL 的容器和算法库。其中有序的 Map 选择用跳表来实现,并优化到了相当好的性能。在此分享一下优化的思路和心得,供大家参考借鉴,如果发现有错误也欢迎指出。 一、背景 首先为标题党致歉,不过确实没吹牛 😊。 最近一年我所负责的业务系统中,用 Go 语言的实现的占了至少 70%的比例,因此 Review 了大量的 G
腾讯技术工程官方号
2022/09/02
1.9K0
手写了个可能是Github性能最强的Go跳表
Redis源码之跳表数据结构
跳跃表(skiplist)是一种随机化的数据, 由 William Pugh 在论文《Skip lists: a probabilistic alternative to balanced trees》中提出, 跳跃表以有序的方式在层次化的链表中保存元素, 效率和平衡树媲美 —— 查找、删除、添加等操作都可以在对数期望时间下完成, 并且比起平衡树来说, 跳跃表的实现要简单直观得多。
杨永贞
2022/05/07
7580
Redis源码之跳表数据结构
漫谈 LevelDB 数据结构(一):跳表(Skip List)
早对 LevelDB 有所耳闻,这次心血来潮结合一些资料粗略过了遍代码,果然名不虚传 —— 绝对是不世出的工艺品!如果你对存储感兴趣、如果你想优雅使用 C++、如果你想学习如何架构项目,都推荐来观摩一下。谷歌出品,必是精品,更何况作者是 Sanjay Ghemawat 和 Jeff Dean 呢。看过一遍如果不输出点什么,以我的记性,定会很快抛诸脑后。便想写点东西说说 LevelDB 之妙,但又不想走寻常路,从架构概览说起,以模块分析做合。读代码的这些天,一直在盘算从哪下笔比较好。在将将读完之时,印象最深的反而是 LevelDB 的各种精妙的数据结构:贴合场景、从头构建、剪裁得当、代码精到。不妨, LevelDB 系列就从这些边边角角的小构件开始吧。本系列主要想分享 LevelDB 中用到的三个工程中常用的经典数据结构,分别是用以快速读写 memtable 的 Skip List、用以快速筛选 sstable 的 Bloom Filter 和用以部分缓存 sstable 的 LRUCache 。这是第一篇,Skip List。
木鸟杂记
2021/09/26
1.4K0
详解全网最快Go泛型跳表【内附源码】
导读| 今年开发者期盼已久的、泛型的go1.18发布了,但目前基于泛型的容器实现案例很稀缺。腾讯后台开发工程师陈峰实现了一套类似C++中STL的容器和算法库。其中有序的Map用跳表实现,并优化到极致性能。本文作者将分享优化的思路并公开源码,供各位开发者参考。
腾讯云开发者
2022/12/31
7610
详解全网最快Go泛型跳表【内附源码】
golang刷leetcode 经典(4) 实现跳表
跳表是在 O(log(n)) 时间内完成增加、删除、搜索操作的数据结构。跳表相比于树堆与红黑树,其功能与性能相当,并且跳表的代码长度相较下更短,其设计思想与链表相似。
golangLeetcode
2022/08/02
2540
golang刷leetcode 经典(4) 实现跳表
数据结构【单链表基本操作】
包含单链表的创建、遍历、反转(指针替换、递归)、排序、插入、删除 // list_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "pch.h" #include <iostream> #include <stdio.h> #include <stdlib.h> #include <malloc.h> using namespace std; typedef struct Node { int nData; //数据域 No
Sky_Mao
2020/07/24
3910
零基础手把手带你阅读Redis源代码系列-ZSet底层原理详解(跳表SkipList)
为什么不存全部数据?部分数据会修改,那么可能导致value伪重复,加大了业务复杂度
Karos
2023/07/23
1.8K2
零基础手把手带你阅读Redis源代码系列-ZSet底层原理详解(跳表SkipList)
如果面试官问你“跳表”,这一篇直接往他嘴里怼就行了
大家好啊,摸完3月的?,果然4月要加倍还回去。前段时间脑子一热,我翻译了一篇《Skip Lists: A Probabilistic Alternative to Balanced Trees》。 我
老李秀
2021/05/13
1.1K0
如果面试官问你“跳表”,这一篇直接往他嘴里怼就行了
相关推荐
data_structure_and_algorithm -- 跳表:python & java & c-cpp 实现
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
加入讨论
的问答专区 >
职务职务职务职务职务职务擅长3个领域
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档