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

郑州地方网络推广网站浦东做网站的公司

郑州地方网络推广网站,浦东做网站的公司,沈阳企业建站系统模板,互联网公司招聘信息文章目录 1. 什么是LRU Cache2. LRU Cache的实现3. LRU Cache的OJ题目分析AC代码 1. 什么是LRU Cache LRU是Least Recently Used的缩写#xff0c;意思是最近最少使用#xff0c;它是一种Cache替换算法。 什么是Cache#xff1f; 狭义的Cache指的是位于CPU和主存间的快速RAM… 文章目录 1. 什么是LRU Cache2. LRU Cache的实现3. LRU Cache的OJ题目分析AC代码 1. 什么是LRU Cache LRU是Least Recently Used的缩写意思是最近最少使用它是一种Cache替换算法。 什么是Cache 狭义的Cache指的是位于CPU和主存间的快速RAM 通常它不像系统主存那样使用DRAM技术而使用昂贵但较快速的SRAM技术。 广义上的Cache指的是位于速度相差较大的两种硬件之间 用于协调两者数据传输速度差异的结构。除了CPU与主存之间有Cache 内存与硬盘之间也有Cache乃至在硬盘与网络之间也有某种意义上的Cache── 称为Internet临时文件夹或网络内容缓存等。 而Cache的容量有限那如果cache满了怎么办 当Cache的容量用完后而又有新的内容需要添加进来时 就需要挑选并舍弃原有的部分内容从而腾出空间来放新内容。 那应该选取那一部分的内容和新内容进行替换呢这就涉及到cache的替换算法而LRU Cache就是cache替换算法中的一种 LRU Cache 的替换原则就是将最近最少使用的内容替换掉。其实LRU译成最久未使用会更形象 因为该算法每次替换掉的就是一段时间内最久没有使用过的内容。 2. LRU Cache的实现 那要实现一个LRU Cache其实并不难方法和思路有很多但是想要实现一个高效所有操作都是O(1) 的LRU Cache是有难度的 实现LRU Cache的方法和思路很多但是要保持高效实现O(1)的put和get那么使用双向链表和哈希表的搭配是最高效和经典的。 使用双向链表是因为双向链表可以实现任意位置O(1)的插入和删除使用哈希表是因为哈希表的增删查改也是O(1)。 那具体到底应该应该怎么做呢 下面我们借助LeetCode上的一道OJ来给大家进行一个详细的讲解。 3. LRU Cache的OJ 题目链接: link 我们来看一下题目 大家可以自己先看一下题目我们看到题目中要求函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。 那我们来分析一下要如何实现 题目分析 题目要求我们实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 这个 LRUCache 类的要求是这样的 那我们要如何实现呢 其实分析完题目我们很容易能想到用哈希表那当然C里面我们就用unordered_map去搞那这样的话get函数其实就是查找嘛就能达到O(1)然后put呢put也是要查找嘛找到就更新找不到就插入。那这样就也是O(1)。 但是呢我们真正还要考虑还有——如果插入操作导致关键字数量超过 capacity 我们此时就要进行LRU替换则应该 逐出 最久未使用的关键字。 那我们要如何实现LRU的替换呢满的话应该逐出谁啊如何找到最久未被使用的那个呢 那上面也提到了使用双向链表和哈希表的搭配是最高效和经典的 我们再搞一个listlist底层就是带头双向循环链表让它里面也存储数据相当于数据存储两份然后我们可以默认认为尾部的那个元素就是最近最少用最久未被使用的按头部实现也可。 然后如果有新插入的元素或者被访问get一个已有的值的元素我就把它移到链表头部。 这样我们需要替换的时候那么链表尾部的那个就是最久未被使用的那个。 但是呢 如果我们就这样设计的话还存在一个问题。 就是更新的时候其实复杂度是O(N)。 为什么呢 更新的情况就是调用put先在哈希表里面查找到key是已存在的那然后我们要修改哈希表里面我找到这个就可以直接修改。 但是在list里面我们是不是也要修改啊因为我们替换的时候找最久未被使用的那个值就是要从list里面找呢。 但是要修改list的话我们知不知道当前要修改的这个元素是list里面的哪一个元素 是不知道的所以还得遍历list去找。找到之后更新一下然后把它移到头部去更新顺序。 那这里遍历查找的话不就是O(N)了嘛。 那这个问题我们如何解决一下呢 如何做到在哈希表里面找到这个key之后就直接能获取到他在list中的位置而不需要去遍历查找呢 那这里有一个非常巧的设计是这样来解决的 还是list和unordered_map搭配。 list里面呢还是存key-value的键值对pair。然后哈希表里面key还是要存的但是不再像上面写的那样直接存key对应的数据value而是存这个key对应的元素在list里面的对应的迭代器。那这样真正的数据就只存在list里面 那这样的话如果更新的话首先我们在哈希表里面找到key然后通过它里面存的该元素在list中的迭代器就可以直接修改list里面存放的数据。 然后再把它放到链表头部两种方法后面会提到。 当然listpairint,int::iterator这个类型比较长我们也可以typedef一下 那下面我们来尝试写一下代码 AC代码 那首先我们应该还要再增加一个成员变量 即cache的容量capactity因为有时候我们还需要判断cache满不满。 然后我们来逐一实现一下它的3个成员函数 首先是它的构造函数LRUCache 那这个很简单就是初始化一下capacity就行了。 剩下两个成员变量是自定义类型有默认构造。 那然后是get函数 get呢也很简单就是通过key判断在不在嘛。 如果在的话就返回key对应的值如果不在返回-1。 那我们就可以直接调用unordered_map的find函数根据find的返回结果判断如果找到了我们要返回什么呢 首先这里的ret是啥啊这里find返回的是迭代器找到的话返回的就是key对应的这个元素的迭代器。 那我们要返回这个key对应的那个有效的值那真正的数据是存在list里面的。 我们通过谁可以找到list里面存储的这个key对应的元素呢 现在unordered_map里面的value存的是list里面这个key对应元素的迭代器有点绕了这里。 所以ret-second就是list里面这个元素的迭代器但是我们想要拿到的是这个元素的key对应的值即ret-second-second这里要取两次second。 那这样就完了嘛 还没有。 如果get的时候成功找到了这个数据那相当于访问了它那cache里面存储数据的顺序是不是就要调整了。是不是要把这个刚被访问的元素放到链表头部啊。 那如何在list里面调整这个顺序呢我们上面提到有两种方式 首先第一种方法我们可以先把这个元素删除掉然后在头插到头部。 但是这样的话记得还要更新一下unordered_map里面存的对应的那个迭代器因为删完之后这个迭代器就失效了。之前的文章我们模拟实现过list我们知道list的迭代器其实就是对结点指针的封装嘛这个结点删除的话它这个结点指针指向的空间就释放了。 所以这种方法好像有点麻烦。 那我就可以考虑用另外一种——直接调用list的splice 接口转移结点。 那splice 这个函数其实我们之前也有提到过 它可以把一个链表的一部分转移到另一个链表当然也可以是同一个链表直接进行转移 所以我们就可以直接调用splice将这个结点转移到list的头部。 那最后就剩下put 那put的话呢无非就两种操作 如果关键字 key 已经存在则变更其数据值 value 如果不存在则向缓存中插入该组 key-value 。 当然插入的时候需要判断 如果插入操作导致关键字数量超过 capacity 则应该 逐出 最久未使用的关键字然后插入新值。 另外不论是插入还是更新都应该把插入或更新的值放到链表头部。 那我们来写一下代码 那到这里就完事了。 我们来提交一下 没有问题 完整代码 class LRUCache { public:LRUCache(int capacity):_capacity(capacity){}int get(int key) {auto ret_hashmap.find(key);if(ret!_hashmap.end()){LtIter itret-second;//将it对应的结点转移到链表头部_LRUList.splice(_LRUList.begin(),_LRUList,it);return it-second;}return -1;}void put(int key, int value) {auto ret_hashmap.find(key);//如果找到更新值if(ret!_hashmap.end()){LtIter itret-second;it-secondvalue;//将it对应的结点转移到链表头部_LRUList.splice(_LRUList.begin(),_LRUList,it);}else//找不到插入{//如果满了需要先删除最久未使用的值if(_capacity_hashmap.size()){pairint,int back_LRUList.back();_hashmap.erase(back.first);_LRUList.pop_back();}//插入_LRUList.push_front(make_pair(key,value));_hashmap[key]_LRUList.begin();}} private:typedef listpairint,int::iterator LtIter;//hash做到查找更新/插入是O(1)unordered_mapint, LtIter _hashmap;//LRU 默认链表尾部的是最久未被使用的listpairint, int _LRUList;size_t _capacity; };那我们这篇文章就到这里…
http://www.dnsts.com.cn/news/124957.html

相关文章:

  • 广东省建筑网站邱县网站建设
  • 网站建设怎么设置渐变色广州做网站好的公司
  • 网站开发前端好还是后端好网站建设网络推广首选公司
  • 招聘网站做竞品分析电子商务网站的设计要求包括
  • 典型的网站案例订单网站模块
  • 世界上前端做的最好的网站恩施做网站
  • 南昌淘宝网站制作公司极验验证+wordpress
  • 怎么做网站超链接大连企业网站建设
  • 个人域名备案网站名称网站模板怎么弄的
  • 淘宝网站开发源码数据库网站开发外文翻译
  • 免费网站制作软件平台南京网站搜索优化
  • 网站开发需要哪些知识大型集团网站建设公司
  • 网页是网站吗最新网页游戏开服时间表
  • 石嘴山住房和城乡建设厅网站产品代理网
  • 企业电器网站建设方案长沙优化官网公司
  • 群团组织网站建设wordpress 数据库连接文件
  • 沈阳网站建设信息微网站的建设第一步是什么
  • 网站建设和维护视频做分色找工作网站
  • 源美网站建设开发一个电商网站
  • 网站建设应该怎么做医疗ppt模板下载免费完整版
  • 在线设计网站排名网站建设克隆
  • 做房产网站有哪些wordpress视频主题汉化
  • 网站设计师是什么网站备案 是域名还是空间
  • 云南seo简单整站优化wordpress模板yunnut
  • 做网站每一年都要交钱吗校园网站开发的需求和分析
  • 眉山 网站开发滨江区建设局网站
  • 网站备案 企业备案站长工具查询官网
  • 购物网站怎么做代码龙华在深圳算什么档次
  • 天津百度搜索网站排名百度seo公司哪家强一点
  • 深一互联网站建设怎样长沙部分风险区域调整