左神算法进阶班5_4设计可以变更的缓存结构(LRU)
【题目】
设计一种缓存结构,该结构在构造时确定大小,假设大小为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_5BFPRT算法
在无序数组中找到第k大的数1)分组,每N个数一组,(一般5个一组)2)每组分别进行排序,组间不排序3)将每个组的中位数拿出来,若偶数,则拿上 / 下中位数, 成立一个一个新数组.4)新数组递归调用BF ...
- 左神算法基础班5_1设计RandomPool结构
Problem: 设计RandomPool结构 [题目] 设计一种结构,在该结构中有如下三个功能: insert(key):将某个key加入到该结构,做到不重复加入. delete(key):将原本在 ...
- 左神算法进阶班3_1构造数组的MaxTree
题目 一个数组的MaxTree定义: 数组必须没有重复元素 MaxTree是一棵二叉树,数组的每一个值对应一个二叉树节点 包括MaxTree树在内且在其中的每一棵子树上,值最大的节点都是树的头 给定一 ...
- 左神算法进阶班8_1数组中累加和小于等于aim的最长子数组
[题目] 给定一个数组arr,全是正数:一个整数aim,求累加和小于等于aim的,最长子数组,要求额外空间复杂度O(1),时间复杂度O(N) [题解] 使用窗口: 双指针,当sum <= aim ...
- 左神算法进阶班1_4Manacher算法
#include <iostream> #include <string> using namespace std; //使用manacher算法寻找字符中最长的回文子串 in ...
- 左神算法进阶班1_1添加最少字符得到原字符N次
Problem: 给定一个字符串str1,只能往str1的后面添加字符变成str2. 要求1:str2必须包含两个str1,两个str1可以有重合,但是不能以同一个位置开头. 要求2:str2尽量短最 ...
- 左神算法进阶班4_2累加和为aim的最长子数组
[题目] 给定一个数组arr,和一个整数aim,求在arr中,累加和等于num的最长子数组的长度 例子: arr = { 7,3,2,1,1,7,7,7 } aim = 7 其中有很多的子数组累加和等 ...
- 左神算法进阶班6_1LFU缓存实现
[题目] LFU也是一个著名的缓存算法,自行了解之后实现LFU中的set 和 get 要求:两个方法的时间复杂度都为O(1) [题解] LFU算法与LRU算法很像 但LRU是最新使用的排在使用频率最前 ...
- 左神算法基础班4_1&2实现二叉树的先序、中序、后序遍历,包括递归方式和非递归
Problem: 实现二叉树的先序.中序.后序遍历,包括递归方式和非递归方式 Solution: 切记递归规则: 先遍历根节点,然后是左孩子,右孩子, 根据不同的打印位置来确定中序.前序.后续遍历. ...
随机推荐
- 【牛客网多校第一场】A
题目链接:https://www.nowcoder.com/acm/contest/139/A 题意:大概就是给你0,1,2让你填矩阵问有多少种填法满足 a(i,j)<=a(i+1,j)以及a( ...
- 网页设计师神器,快速生成网站配色、字型等风格的工具——Stylify Me
在设计网页时,最重要的一项便是网页的配色,颜色的使用在网页制作中起着非常关键的作用,不同的网站有着自己不同的风格,也有着自己不同的颜色.今天给大家介绍一个在线生成网站配色的工具——Stylify Me ...
- ES6 学习 -- Class继承
(1)如何继承Class可以通过extends关键字实现继承,如下:class Father { } class Child extends Father { }// 这里子类Child继承父类Fat ...
- iOS进阶五-RunLoop
简介 RunLoop 运行循环.跑圈 RunLoop的作用主要体现在三方面: 1.保持程序持续运行 2.处理App中的各种事件(比如触摸事件.定时器事件.Selector事件) 3.节省CPU资源,提 ...
- Django ORM 之基于对象、双下划线查询
返回ORM目录 Django ORM 内容目录: 一. 基于对象的表查询 二. 基于双下划线的查询 三. 聚合查询 aggregate 四. 分组查询 annotate 一. 基于对象的表查询 1.正 ...
- JS事件 卸载事件 当用户退出页面时(页面关闭、页面刷新等),触发onUnload事件,同时执行被调用的程序。注意:不同浏览器对onunload事件支持不同。
卸载事件(onunload) 当用户退出页面时(页面关闭.页面刷新等),触发onUnload事件,同时执行被调用的程序. 注意:不同浏览器对onunload事件支持不同. 如下代码,当退出页面时,弹出 ...
- SQL链接EXCEL操作
Sub CopyData_5() Set Cnn = CreateObject("ADODB.Connection")With Cnn.Provider = "micro ...
- Leetcode207. Course Schedule课程表
现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量以及它 ...
- .net下MVC中使用Tuple分页查询数据
主要是在DAL层写查询分页的代码. 例如DAL层上代码: public Tuple<List<WxBindDto>, int> GetMbersInfo(int start, ...
- python 之单例模式
单例模式1 单例=>只有一个单例2 静态方法+静态字段3 所有实例中等转的内容相同时 用单例模式class Sqllite: __instance=None def __init__(self) ...