【题目】

设计一种缓存结构,该结构在构造时确定大小,假设大小为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. 第一个Vus.js

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. Python全栈开发:django网络框架(一)

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...

  3. CF982F The Meeting Place Cannot Be Changed

    题意:给你一张有向图,某人会任意选择起点然后走无穷多步,问是否存在一个点(要求输出)不管他起点在何处怎么走都必经?n<=100005,m<=500005. 标程: #include< ...

  4. lock tables和unlock tables

    1.lock tables table1 read,table2 read,table3 read igoodful@a8-apple-iphone-db00.wh(glc) > show ta ...

  5. IDEA快捷键(收集自网络后整理)

    快捷键 说明 CTRL+B 快速打开光标处的类或方法 CTRL+C 拷贝 CTRL+D 复制当前行到下一行 CTRL+E 最近打开的文件 CTRL+F 当前文件查找特定内容 CTRL+G 定位行 CT ...

  6. Perl 标量

    Perl 标量 标量是一个简单的数据单元. 标量可以是一个整数,浮点数,字符,字符串,段落或者一个完整的网页. 以下实例演示了标量的简单应用: 实例 #!/usr/bin/perl $age = 20 ...

  7. 1 A+B问题

    原题网址: http://www.lintcode.com/zh-cn/problem/a-b-problem/# 给出两个整数a和b, 求他们的和, 但不能使用 + 等数学运算符. 注意事项 你不需 ...

  8. 深入浅出Java中的clone克隆方法,写得太棒了!

    作者:张纪刚 blog.csdn.net/zhangjg_blog/article/details/18369201/ Java中对象的创建 clone 顾名思义就是 复制 , 在Java语言中, c ...

  9. <每日一题>题目11:以文件夹名称作为参数,返回该文件夹下所有文件的路径

    ''' 分析: 1.知道文件夹名称(假设是形如:E:\\software\\Notepad++),很显然可以通过OS模块去求 2.OS.listdir(sPath),列出文件夹内所有的文件和文件夹,以 ...

  10. webpack 简单笔记(三)vue-cli 使用 webpack-bundle-analyzer 分析

    当我们使用CommonsChunkPlugin插件时可以使用webpack-bundle-analyzer插件来分析分块是否达到我们的目地 安装 npm install --save-dev webp ...