当前位置:网站首页>Niuke network: Design LRU cache structure design LFU cache structure
Niuke network: Design LRU cache structure design LFU cache structure
2022-06-26 17:17:00 【lsgoose】
Catalog
1. Design LRU Cache structure


This question , Tell the truth , At first, I didn't understand what his input was ...
Look at the instructions , It seems like this again , It is to create a class and directly call the methods inside :
In fact, it is to maintain a two-way linked list , Yes XV6 The memory and lock of the operating system should be known by students LRU What the hell is that? . The idea is as follows :
Whole LRU Maintain a linked list and a hash table , Linked list can be used directly list Double linked list , Hash table with unordered_map To design , The hash table stores key And the iterator in the linked list .
Get
First , about get operation , The function is like this : For a given key, We want to check whether it exists in the linked list , Here hash can be implemented O(1) Cost of searching time , The process is as follows :
1. Find if it exists key Corresponding node , If not, return directly to -1
2. otherwise , Let's start with key Get the corresponding node from the hash , Then delete the corresponding node .
the reason being that LRU, So we should put the most recently used ones at the top ( Although the hash table is used, it is based on LRU We still have to put our ideas at the front ), So we put the extracted node in the head of the linked list , And then create in the hash table <key, list.begin()> The mapping relation of .
Finally, the header node is returned value
Set
about set operation , The function is like this : For a given <key, value>, If it exists in the linked list key The node of , Then modify it and put it in the chain header , If it doesn't exist , Then directly add the node in front as the chain header , Also consider whether the linked list will explode , If the capacity has reached , So according to LRU Principles , Let's delete the tail of the linked list first
The code is as follows :
class Solution {
public:
list<pair<int, int>> dlist;
unordered_map<int, list<pair<int, int>>::iterator> map;
int cap;
Solution(int capacity){
cap=capacity;
}
int get(int key) {
// write code here
if(map.count(key)){
auto tmp=*map[key];
dlist.erase(map[key]);
dlist.push_front(tmp);
map[key]=dlist.begin();
return dlist.front().second;
}
return -1;
}
void set(int key, int value){
if(map.count(key)){
dlist.erase(map[key]);
}else if(cap==dlist.size()){
auto tmp=dlist.back();
map.erase(tmp.first);
dlist.pop_back();
}
dlist.push_front(pair<int, int>(key, value));
map[key]=dlist.begin();
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* solution = new Solution(capacity);
* int output = solution->get(key);
* solution->set(key,value);
*/Of course , In addition to using the data structure in the standard library , We can also create a two-way linked list by ourselves , We need to isolate a function that moves the node to the header , So that when we are doing get Operation found a node , perhaps set The corresponding node is placed in the header .
The code is as follows , There are many details to pay attention to , It mainly updates the data structure and hash :
#include<bits/stdc++.h>
using namespace std;
struct Node{
int key;
int val;
Node *prev;
Node *next;
Node(int key, int val) : key(key), val(val), next(NULL), prev(NULL) {}
};
class Solution {
public:
unordered_map<int, Node*> hash;
Node *head;
Node *tail;
int cap;
int size;
Solution(int capacity){
head=NULL;
tail=NULL;
cap=capacity;
size=0;
hash.clear();
}
// Put a node in the header
// If at the tail The tail node needs to be updated
// After moving to the header, you need to update the pointer and the header node
void removeToHead(Node *p){
// The first change
if(p==head){
return;
}
p->prev->next=p->next;
if(p==tail){
tail=p->prev;
}else{
p->next->prev=p->prev;
}
p->prev=NULL;
p->next=head;
head->prev=p;
head=p;
return;
}
int get(int key) {
if(hash.find(key)==hash.end()){
return -1;
}
removeToHead(hash[key]);
return hash[key]->val;
}
void set(int key, int value){
if(hash.find(key)!=hash.end()){
hash[key]->val=value;
removeToHead(hash[key]);
}else if(size>=cap){
// Update the tail node to the current node Move to the head
// Update hash table Delete the original Add new
int k=tail->key;
hash.erase(k);
tail->key=key;
tail->val=value;
removeToHead(tail);
hash[key]=head;
}else{
// No node exists And the capacity is not full Insert directly into the head
Node *node=new Node(key, value);
if(head==NULL){
head=tail=node;
}else{
node->next=head;
node->prev=NULL;
head->prev=node;
head=node;
}
hash[key]=head;
size++;
}
}
};2. Design LFU Cache structure
above LRU Is the least recently used strategy ,LFU yes least frequently used, Literally, it seems to be the least used strategy recently , But from the title , Yes, let's also record the use of set and get The number of times .
We use a double hash table to solve this problem , At the same time, I saw a well drawn picture in the solution :

This is the data structure we want to maintain . First , For each frequency , We maintain a two-way linked list , This bi-directional linked list represents the set of nodes with corresponding frequencies , What's stored is {freq, key, value}, This forms a hash table of frequencies and linked lists . Based on this hash table, we can easily find the two-way linked list according to frequency , When the capacity is insufficient, it is very fast to find the deleted node . Secondly, it is also convenient for some update operations to delete inserts . It is also due to deleting nodes when the capacity is insufficient , We need a variable to store freq The smallest node .
The second hash table is key And the hash table of linked list nodes , This hash table is for get Operation is very necessary .
Next, analyze get and set The process of operation :
Get
get The function of the operation is based on key look for value, With the hash table , We can directly base on key Find the corresponding node , And then find value, Return if not found -1.
Set
set The function of the operation is to set <key, value>, The process is as follows :
1. If this mapping relationship existed before , So let's update the mapping , About what updates are , Then say .
2. If it doesn't exist , We are going to insert this new mapping , Of course , Also consider whether the current linked list is full , So we also need to maintain a variable that records the remaining space .
a. If it's already full , We need to do something :
First, find the node with the lowest frequency and the least use , For the node with the lowest frequency , Since we maintain the frequency and the hash of the set of corresponding nodes , We'll soon find , For minimum use , Each time we update it, we put it in the header , So the last node is the least used .
After finding the node, we need to delete it , After deletion, we have to check whether the linked list is empty , If it is empty, you have to delete the mapping item directly .
b. If it's not full , Let's maintain the remaining capacity
And then directly to freq=1 Insert a new... Into the head of the two-way linked list <freq=1, key, value>, After that, the corresponding <key,value> mapping .
Update
The update operation is used in set There is already a corresponding key Or, for an existing node get when , Update its frequency .
First , We according to the key Take out the linked list node , Then according to the... In the linked list node freq Find the corresponding linked list , Then directly delete the corresponding node in the linked list .
If the linked list becomes empty after deletion :
Delete the mapping relationship , Let's see if we need to update the minimum frequency , If the deleted list is the list corresponding to the minimum frequency , So it needs to be updated
Finally the new <freq+1,key,value> Insert the corresponding linked list , If it is set It needs to be updated map
The specific code is as follows :
class Solution {
public:
/**
* lfu design
* @param operators int integer vector<vector<>> ops
* @param k int integer the k
* @return int integer vector
*/
// Store the frequency and the dictionary of the node linked list corresponding to the frequency
unordered_map<int, list<vector<int>>> freq_mp;
// Save the corresponding key value and node
unordered_map<int, list<vector<int>>::iterator> mp;
// Record the minimum frequency To use LFU Policy find node
int min_freq=0;
// Remaining storage capacity
int size=0;
vector<int> LFU(vector<vector<int>>& operators, int k){
vector<int> res;
size=k;
for(int i=0;i<operators.size();++i){
if(operators[i][0]==1){
set(operators[i][1], operators[i][2]);
}else{
res.push_back(get(operators[i][1]));
}
}
return res;
}
void update(list<vector<int>>::iterator iter, int key, int value){
// Take a node from the bidirectional linked list namely vector<int>
int freq=(*iter)[0];
freq_mp[freq].erase(iter);
// If there are no nodes in the frequency
// Delete the corresponding linked list in the frequency bidirectional linked list
// See if you need to update the minimum frequency
if(freq_mp[freq].empty()){
freq_mp.erase(freq);
if(freq == min_freq){
min_freq++;
}
}
// towards freq+1 In the head of the bidirectional linked list
// Because the original node no longer exists It needs to be reset <key,value> The storage
freq_mp[freq+1].push_front({freq+1, key, value});
mp[key]=freq_mp[freq+1].begin();
}
void set(int key, int value){
auto it=mp.find(key);
if(it!=mp.end()){
// There are nodes in the linked list to update value And frequency
update(it->second, key, value);
}else{
// The node does not exist in the hash table
// If the list is full The most frequent and earliest deletion
// Delete the last node in the frequency table
// Delete the corresponding <key,value> The node of
if(size==0){
int oldkey=freq_mp[min_freq].back()[1];
freq_mp[min_freq].pop_back();
if(freq_mp[min_freq].empty()){
freq_mp.erase(min_freq);
}
mp.erase(oldkey);
}else{
// Under capacity You can directly join
size--;
}
min_freq=1;
freq_mp[1].push_front({1, key, value});
mp[key]=freq_mp[1].begin();
}
}
//get operation : If not found, return -1
// If found, update the frequency and take out value return
int get(int key){
int res=-1;
auto it = mp.find(key);
if(it==mp.end()){
return res;
}
auto iter = it->second;
res=(*iter)[2];
update(iter, key, res);
return res;
}
};Have to say , The combination of data structure and corresponding storage is really a clever thing ~
边栏推荐
- Leetcode daily [2022 - 02 - 16]
- Can Luo Yonghao succeed in entering the AR field this time?
- The texstudio official website cannot be opened
- Teach you to learn dapr - 8 binding
- Prometeus 2.34.0 新特性
- MySQL index
- 物联网协议的王者:MQTT
- 在国金证券开户怎么样?保障安全吗?
- Redis OM . Net redis object mapping framework
- Inspirational. In one year, from Xiaobai to entering the core Department of Alibaba, his counter attack
猜你喜欢

Leetcode 1170. Frequency of occurrence of the minimum letter of the comparison string (yes, solved)

Platform management background and merchant menu resource management: access control design of platform management background

Redis' 43 serial cannons, try how many you can carry

Microservice architecture practice: user login and account switching design, order query design of the mall

牛客网:设计LRU缓存结构 设计LFU缓存结构

Leetcode 1169. Query invalid transactions (if the amount of data is small, this problem still needs to be solved by violent enumeration)

Ndroid development from introduction to mastery Chapter 2: view and ViewGroup

Fire evacuation and self rescue... This safety production and fire training is full!

Web3 decentralized storage ecological landscape

Romance of the Three Kingdoms: responsibility chain model
随机推荐
Distributed Architecture Overview
Calculate the average of N numbers in the index group of X, and return the number that is less than the average and closest to the average through formal parameters
Microservice architecture practice: business management background and SSO design: SSO design
【推荐系统学习】推荐系统架构
Leetcode 1170. 比较字符串最小字母出现频次(可以,已解决)
vue--vuerouter缓存路由组件
Use FST JSON to automatically generate faster JSON serialization methods
Decentralized NFT transaction protocol will defeat opensea
关于FlowUs这一款国民好笔记
20: Chapter 3: develop the pass service: 3: get through the redis server in the program; (it only connects with the redis server and does not involve specific business development)
Microservice architecture practice: business management background and SSO design, SSO client design
Teach you to learn dapr - 3 Run the first with dapr Net program
去中心化NFT交易协议将击败OpenSea
Microservice architecture practice: user login and account switching design, order query design of the mall
[suggested collection] 11 online communities suitable for programmers
[matlab project practice] prediction of remaining service life of lithium ion battery based on convolutional neural network and bidirectional long short time (cnn-lstm) fusion
Comp281 explanation
Find all primes less than or equal to Lim, store them in AA array, and return the number of primes
Call the random function to generate 20 different integers and put them in the index group of institute a
离婚协议中的几个重点