【题目】

设计一种缓存结构,该结构在构造时确定大小,假设大小为K,并有两个功能:

set(key, value):将记录(key, value)插入该结构。

get(key):返回key对应的value值。

【要求】

1.set和get方法的时间复杂度为O(1)。

2.某个key的set或get操作一旦发生,认为这个key的记录成了最经常使用的。

3.当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。

【举例】

假设缓存结构的实例是cache,大小为3,并依次发生如下行为:

1.cache.set("A", 1)。最经常使用的记录为("A", 1)。

2.cache.set("B", 2)。最经常使用的记录为("B", 2),("A", 1)变为最不经常的。

3.cache.set("C", 3)。最经常使用的记录为("C", 3),("A", 1)还是最不经常的。

4.cache.get("A")。最经常使用的记录为("A", 1),("B", 2)变为最不经常的。

5.cache.set("D", 4)。大小超过了3,所以移除此时最不经常使用的记录("B", 2),

加入记录("D", 4),并且为最经常使用的记录,然后("C", 3)变为最不经常使用的

记录

【题解】

储存数据用hash_map,因为hash表的增删该查的复杂度都为O(1)

本来使用频率使用队列存储,使用的放在头,不使用的自动向后排,最不经常使用的在队尾

但每次从队列中取出正在使用的数据至队列头部的复杂度为O(N),不满足条件

所以只能使用双向链表来进行存储,

hash表中存放着每个数据节点的地址参数,故链表的中数据位置调整复杂度为O(1)

最经常使用的数据节点在链表的尾部,不经常使用的在链表的尾部,因为缓存数据时需要经常使用的,

而链表的尾部插入更加方便。

【代码】

  

 #pragma once
 #include <iostream>
 #include <hash_map>
 #include <deque>

 using namespace std;

 #define M 5//缓存空间的大小
 struct Node
 {
     int val;//数据存在链表中, 索引存在表中
     char c;
     Node* pre;
     Node* next;
     Node(char c, int a) :c(c), val(a), pre(nullptr), next(nullptr) {}
 };

 class Cash
 {
 public:
     void set(const char c, const int a);
     int get(const char c);

 private:
     void update(Node* p);//更新使用频率
     hash_map<char, Node*>map;
     Node* head = );//指向链表的头
     Node* end = head;//指向链表的尾
 };

 void Cash::update(Node* p)
 {
     if (p == end)
         return;//p在链表尾部就不用移动了
     Node* q = p->pre;
     q->next = p->next;
     p->next->pre = q;
     end->next = p;
     p->pre = end;//更新p的使用率,并挪至链表尾部
     end = p;
 }

 void Cash::set(const char c, const int a)
 {
     if (map.find(c) == map.end())//不存在就存入
     {
         if (this->map.size() == M)//缓存空间已满
         {
             Node* p = this->head->next;
             this->head->next = p->next;//删除位于链表头部的最不常用的节点
             if (p->next == nullptr)//只有一个数据
                 end = head;
             else
                 p->next->pre = head;
             map.erase(p->c);//从表中删除,以留出空间
             delete p;
         }
         Node* p = new Node(c, a);//新插入的数据在链表尾
         this->end->next = p;
         p->pre = end;
         end = p;
         map[c] = p;//存入数据
     }
     else//存在,但要更新数的使用频率
     {
         Node* p = map[c];//得到在链表中的位置
         p->val = a;//更新数据值
         update(p);//更新使用频率
     }
 }

 int Cash::get(const char c)
 {
     if (map.find(c) == map.end())
     {
         cout << "the data is not existe!" << endl;
         ;
     }
     Node* p = map[c];
     update(p);//更新使用频率
     return p->val;
 }

 void Test()
 {
     Cash v;
     v.);
     v.);
     v.);
     v.);
     v.);
     v.);
     cout << v.get('A') << endl;

     cout << v.get('B') << endl;
     v.);
     cout << v.get('B') << endl;
     cout << v.get('C') << endl;

 }

左神算法进阶班5_4设计可以变更的缓存结构(LRU)的更多相关文章

  1. 左神算法进阶班1_5BFPRT算法

    在无序数组中找到第k大的数1)分组,每N个数一组,(一般5个一组)2)每组分别进行排序,组间不排序3)将每个组的中位数拿出来,若偶数,则拿上 / 下中位数, 成立一个一个新数组.4)新数组递归调用BF ...

  2. 左神算法基础班5_1设计RandomPool结构

    Problem: 设计RandomPool结构 [题目] 设计一种结构,在该结构中有如下三个功能: insert(key):将某个key加入到该结构,做到不重复加入. delete(key):将原本在 ...

  3. 左神算法进阶班3_1构造数组的MaxTree

    题目 一个数组的MaxTree定义: 数组必须没有重复元素 MaxTree是一棵二叉树,数组的每一个值对应一个二叉树节点 包括MaxTree树在内且在其中的每一棵子树上,值最大的节点都是树的头 给定一 ...

  4. 左神算法进阶班8_1数组中累加和小于等于aim的最长子数组

    [题目] 给定一个数组arr,全是正数:一个整数aim,求累加和小于等于aim的,最长子数组,要求额外空间复杂度O(1),时间复杂度O(N) [题解] 使用窗口: 双指针,当sum <= aim ...

  5. 左神算法进阶班1_4Manacher算法

    #include <iostream> #include <string> using namespace std; //使用manacher算法寻找字符中最长的回文子串 in ...

  6. 左神算法进阶班1_1添加最少字符得到原字符N次

    Problem: 给定一个字符串str1,只能往str1的后面添加字符变成str2. 要求1:str2必须包含两个str1,两个str1可以有重合,但是不能以同一个位置开头. 要求2:str2尽量短最 ...

  7. 左神算法进阶班4_2累加和为aim的最长子数组

    [题目] 给定一个数组arr,和一个整数aim,求在arr中,累加和等于num的最长子数组的长度 例子: arr = { 7,3,2,1,1,7,7,7 } aim = 7 其中有很多的子数组累加和等 ...

  8. 左神算法进阶班6_1LFU缓存实现

    [题目] LFU也是一个著名的缓存算法,自行了解之后实现LFU中的set 和 get 要求:两个方法的时间复杂度都为O(1) [题解] LFU算法与LRU算法很像 但LRU是最新使用的排在使用频率最前 ...

  9. 左神算法基础班4_1&2实现二叉树的先序、中序、后序遍历,包括递归方式和非递归

    Problem: 实现二叉树的先序.中序.后序遍历,包括递归方式和非递归方式 Solution: 切记递归规则: 先遍历根节点,然后是左孩子,右孩子, 根据不同的打印位置来确定中序.前序.后续遍历. ...

随机推荐

  1. Codeforces 479【E】div3

    题目链接:http://codeforces.com/problemset/problem/977/E 题意:就是给你相连边,让你求图内有几个环. 题解:我图论很差,一般都不太会做图论的题.QAQ看官 ...

  2. ubuntu自带截图工具

    ubuntu自带的截图工具感觉能够满足基本的截图功能,可以不必安装另外的截图软件. 一般用到的截图类型有三种:全屏.当前活动窗口.自定义区域,其中自定义区域截图是最灵活也是我们用的最多的方式.在ubu ...

  3. kaggle 实战 (1): PCA + KNN 手写数字识别

    文章目录 加载package read data PCA 降维探索 选择50维度, 拆分数据为训练集,测试机 KNN PCA降维和K值筛选 分析k & 维度 vs 精度 预测 生成提交文件 本 ...

  4. 人脸识别-常用的数据库Face Databases From Other Research Groups

    Static/Videos Static Single/Multiple faces Single? Gray/Color Color Resolution Vaious Face pose Fron ...

  5. 玩转gulp之gulp编译less

    用好gulp grunt webpack让前端编程走向自动化,是作为一个前端开发必须学会的技能,不然逼格怎么提升的上去呢... 然后教大家如何用gulp装逼.一点点的学,都是相通的嘛 1. 安装nod ...

  6. Grunt入门

    Grunt 新手一日入门 2014.06.20 前端相关 TOC 1. 用途和使用场景 2. 开发一个任务自动处理器 3. 开始学习 Grunt 3.1. 安装 Grunt 3.2. 生成 packa ...

  7. android GPS: code should explicitly check to see if permission is available

    转载的,感谢作者,由于我找了很久才找到这个解决方法,因此我自己再转一遍 原文链接 https://blog.csdn.net/qinwendou/article/details/77849048 if ...

  8. mybatis中一对一关系映射

    一对一关系中普通的配置方式 一.多表连接查询语句: <select id="selectStudentWithAddress" parameterType="int ...

  9. 牛客集训第七场J /// DP

    题目大意: 在矩阵(只有52种字符)中找出所有不包含重复字符的子矩阵个数 #include <bits/stdc++.h> #define ll long long using names ...

  10. 次短路 /// dijkstra oj1597

    题目大意: 给出一个有向图,求从 顶点a 到 顶点b 的次短路. 第一行是2个正整数 n 和 e,表示该有向图的顶点数和边数.3 < n ≤ 5000 , 3 < e < 40000 ...