当前位置: 首页 > wzjs >正文

个人建 行业 网站广州竞价托管公司

个人建 行业 网站,广州竞价托管公司,无货源电商,维护一个网站的费用Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

         Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!

我的博客:<但凡.

我的专栏:《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C++修炼之路》

欢迎点赞,关注!

目录

1、跳表引入

        1.1、背景

        1.2、跳表的基本原理

2、跳表模拟实现

        2.1、跳表节点

        2.2、跳表框架

        2.3、 查询

        2.4、 查找前置节点

        2.5、添加节点

        2.6、删除节点

3、跳表的性能分析


1、跳表引入

        1.1、背景

        跳表(Skip List)由美国计算机科学家威廉·普(William Pugh)于1989年提出,目的是解决有序链表查询效率低的问题。传统链表查询时间复杂度为O(n),而跳表通过引入多层索引结构,将查询、插入和删除操作的时间复杂度优化至O(log n),同时保持了较高的空间效率。普的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》奠定了跳表在数据结构领域的地位,成为平衡树轻量级替代方案


        1.2、跳表的基本原理

        跳表的核心思想是通过概率性构建多层索引加速查找。每一层都是有序链表,底层包含所有元素,上层逐步稀疏。稀疏与稠密是通过设置概率不同有所差别。每一个跳表的分布都是随机生成的。查找时从最高层开始,若当前节点的下一个节点值小于目标值,则向右移动;否则向下移动到下一层继续搜索。插入和删除操作通过调整相邻节点的指针实现,并动态维护索引层数。


2、跳表模拟实现

        2.1、跳表节点

        _val存储每个节点存储的值,_nextV指向下一个节点。

struct SkiplistNode
{int _val;vector<SkiplistNode*> _nextV;SkiplistNode(int val, int level):_val(val), _nextV(level, nullptr){}
};

        2.2、跳表框架

        对于跳表类的私有成员变量,有三个,_head是跳表的头,这个节点不存储值。_maxlevel存储最高层高,_p是晋升概率,也就是层高加一的概率。后面会详细说。

class Skiplist
{typedef SkiplistNode Node;
public:Skiplist(){srand(time(0));_head = new Node(-1, 1);}private:Node* _head;size_t _maxLevel = 32;double _p = 0.5;
};

        2.3、 查询

        我们先来说查找,一会在介绍怎么添加节点、

        对于查找的过程来说,我们从头结点开始查找,如果下一个节点的值小于我们想要查找的target,我们就直接跳到下一个节点那。如果下一个节点的值大于我们想要查找的taget,我们就得下降层数。如果层数下降到-1(0层是最低层)也没有找到target值,就跳出循环返回false。

        我们拿一个跳表模拟一下查找的过程:

bool search(int target)
{Node* cur = _head;int level = _head->_nextV.size() - 1;while (level >= 0){if (cur->_nextV[level] && cur->_nextV[level]->_val < target){cur = cur->_nextV[level];}//        走到最后一个节点else if (cur->_nextV[level] == nullptr || cur->_nextV[level]->_val > target){--level;}else{return true;}}return false;
}

        2.4、 查找前置节点

        首先我们先新建一个前置节点,然后把他初始化为level层,其实就是让他的层数和跳表中最高节点的层数相等。我们把这个前置节点的存储的值都初始化为_head。因为如果我们要查找的某个值都比跳表中的所有值都小,那么他的前置节点就是head。

        在循环的过程中,每次调整level我们就记录一下前置节点:

        后序删除和添加节点的时候我们都得先找到前置节点。

vector<Node*> FindPrevNode(int num)
{Node* cur = _head;int level = _head->_nextV.size() - 1;vector<Node*> prevV(level + 1, _head);while (level >= 0){if (cur->_nextV[level] && cur->_nextV[level]->_val < num){cur = cur->_nextV[level];}else if (cur->_nextV[level] == nullptr || cur->_nextV[level]->_val >= num){prevV[level] = cur;--level;}}return prevV;
}

        2.5、添加节点

         再添加节点的操作中,因为我们要控制每个跳表节点的高度都是随机的,所以说我们得先说一下生成随机层高的函数:

        随机数生成部分:

  generator是静态的默认随机数引擎

       用当前系统时间作为种子(time_since_epoch().count()),确保每次程序运行时种子不同static关键字保证在整个程序运行期间只初始化一次

   distribution:静态的均匀实数分布,范围[0.0, 1.0)用于生成0到1之间的随机浮点数。

        p是晋升概率,也就是我们层数++的概率。

        节点层数至少为1。而大于1的节点层数,满足一个概率分布。

        节点层数恰好等于1的概率为1-p。

        节点层数大于等于2的概率为p,而节点层数恰好等于2的概率为p(1-p)。

        节点层数大于等于3的概率为p^2,而节点层数恰好等于3的概率为p^2*(1-p)。

        节点层数大于等于4的概率为p^3,而节点层数恰好等于4的概率为p^3*(1-p)。

int RandomLevel()
{static std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());static std::uniform_real_distribution<double> distribution(0.0, 1.0);size_t level = 1;while (distribution(generator) <= _p && level < _maxLevel){++level;}return level;
}

        接下来我们看添加节点操作。首先我们找到应该插入位置的前置节点,然后依次设置每一层的节点链接。

void add(int num)
{vector<Node*> prevV = FindPrevNode(num);int n = RandomLevel();Node* newnode = new Node(num, n);if (n > _head->_nextV.size()){_head->_nextV.resize(n, nullptr);prevV.resize(n, _head);}for (size_t i = 0;i < n;i++){newnode->_nextV[i] = prevV[i]->_nextV[i];prevV[i]->_nextV[i] = newnode;}
}

        2.6、删除节点

        最后需要注意我们得调整一下头结点的层数。

bool erase(int num)
{vector<Node*> prevV = FindPrevNode(num);if (prevV[0]->_nextV[0] == nullptr || prevV[0]->_nextV[0]->_val != num){//该节点不存在return false;}else{Node* del = prevV[0]->_nextV[0];for (size_t i = 0;i < del->_nextV.size();i++){prevV[i]->_nextV[i] = del->_nextV[i];}delete del;//如果删除了最高层节点,就把头结点层数降一下int i = _head->_nextV.size() - 1;while (i >= 0){if (_head->_nextV[i] == nullptr)--i;elsebreak;}_head->_nextV.resize(i+1);return true;}
}

 

3、跳表的性能分析

        时间复杂度查询、插入、删除均为O(log n),依赖随机层数分布。

        空间复杂度平均O(n),索引节点数量约为n/2 + n/4 +... ≈ n。

        时间复杂度都是由查询操作卡着,而查询操作其实是从上到下遍历一遍。跳表的高度通常为O(log n),其中n是节点数量。

        优势实现简单,无需复杂平衡操作;适合高并发场景(如Redis的有序集合)。

        跳表作为一种高效动态数据结构,兼具实用性与灵活性,是算法设计中的经典案例。

        好了,今天的内容就分享到这,我们下期再见! 

 

http://www.dtcms.com/wzjs/247980.html

相关文章:

  • 公司网站开发怎么做短视频培训
  • 跨境电商的现状及前景太原建站seo
  • 新人做网络咨询的网站系统优化app
  • 青岛做网站建设百度注册公司地址
  • 正规网站建设公司在哪里seo俱乐部
  • 东莞 塑胶 网站建设房管局备案查询网站
  • 怎么制作软件平台免费网站排名优化在线
  • h5个人网站模板源码上海网站排名优化公司
  • 网站开发需要的编程软件营销模式都有哪些
  • 做网站维护有没有前途手机优化大师下载2022
  • 电子商务有什么职业项目优化seo
  • cn域名后缀网站搜索引擎优化理解
  • 建设外贸型网站百度seo排名优化如何
  • 昆明学网站建设网络推广服务合同
  • 网站做百度推广多少钱今日全国最新疫情通报
  • 哪个网站可以做服装批发衣服网站推广优化方案
  • 网站建设在电访销售话术职业培训网络平台
  • 做淘宝客网站必须备案吗重庆seo报价
  • 少儿编程十大骗局上海哪家seo公司好
  • 鄄城网站开发网页加速器
  • 南山做网站联系电话网络销售平台上市公司有哪些
  • dede茶叶网站模板武汉网络优化知名乐云seo
  • 技术支持 深圳网站建设贝尔利河南品牌网站建设
  • 网站备案名可以更改吗湖南seo服务
  • 怎样创建公司网站国内最好用免费建站系统
  • wordpress分类静态天津百度seo推广
  • 怎么做国际货运代理外贸网站百度集团总部在哪里
  • 怎么做网店网站兰州百度推广的公司
  • 搭建视频服务器百度关键词seo
  • 佛山响应式网站开发单页面seo搜索引擎优化