方案一中, 使用队列进行排序, 但是这样做需要每次都要遍历一遍队列, 而如果利用双向链表作为节点存储, 就可以直接将其中的一个node
提前或者删除
解题思路:
- 创建双向链表, 其中的key和value对应cache里面的key和value
- 双向链表的方法包括
- 把一个节点放到双向链表的前面
head
←→node
←→head→next
- 把末尾的节点删除
node→prev
←→node
←→tail
转为 node→prev
←→tail
- 移除节点 直接前驱跟后继向连
- 移动节点到头部 (先移除节点3, 然后将节点加头部1)
struct DoubleLinkedNode {
int key, value;
DoubleLinkedNode *prev;
DoubleLinkedNode *next;
DoubleLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr){}
DoubleLinkedNode(int k, int v):key(k), value(v), prev(nullptr), next(nullptr){}
class LRUCache {
private:
unordered_map<int, DoubleLinkedNode*> temp_;
int capacity_;
DoubleLinkedNode *head_ = nullptr;
DoubleLinkedNode *tail_ = nullptr;
int size_;
public:
LRUCache(int capacity) : capacity_(capacity), size_(0) {
this->head_ = new DoubleLinkedNode();
this->tail_ = new DoubleLinkedNode();
this->head_->next = this->tail_;
this->tail_->prev = this->head_;
int get(int key) {
if(temp_.count(key) == 0){
return -1;
}else{
DoubleLinkedNode* node = temp_[key];
moveTohead(node);
return node->value;
void put(int key, int value) {
if(temp_.count(key) == 0){
DoubleLinkedNode* node = new DoubleLinkedNode(key, value);
temp_[key] = node;
addToHead(node);
size_++;
if(size_ > capacity_){
DoubleLinkedNode* removedNode = removeTail();
temp_.erase(removedNode->key);
delete removedNode;
size_--;
}else{
DoubleLinkedNode* node = temp_[key];
node->value = value;
moveTohead(node);
void addToHead(DoubleLinkedNode* node){
node->prev = head_;
node->next = head_->next;
head_->next->prev = node;
head_->next = node;
void removeNode(DoubleLinkedNode *node){
node->prev->next = node->next;
node->next->prev = node->prev;
DoubleLinkedNode *removeTail(){
DoubleLinkedNode *node = tail_->prev;
removeNode(node);
return node;
void moveTohead(DoubleLinkedNode *node){
removeNode(node);
addToHead(node);
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
当你在某个缓存中存储数据时,常常需要在运行时调整该缓存的大小,以便能容纳更多的数据。
下面是一个增加初始缓存大小的例子:
view plaincopy to clipboardprint?
// console.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <iostream>
#include <algorithm>
using namespace std;
int reallocate(int* &p,
如果我们从网络端接收的数据是不定长度的,不能提前分配好网络缓存大小,则可以选择使用链式缓存的实现方式。链式缓存主要是分配固定大小的缓存链保存数据,一个管理器去管理这些缓存链。
链式缓存示例:
//一种链式缓冲
//ringbuffer是固定长度,不能够扩展,链式buffer可以任意扩充
* buffer
* *first--chain buffer [1024]
* ...
缓存的应用场景和范围十分广泛,下面给出其十分常见的两种应用背景:
首先,在操作系统内部,由于内存资源十分有限,而每个进程又都希望独享一块很大的内存空间。所以诞生了一种“虚拟内存”机制,它将进程的一部分内容暂留在磁盘中,在需要时再进行数据交换将其放入内存,这个过程就需要用到缓存算法机制进行置换。
其次,对于各类应用项目开发而言,在巨大的数据量面前,Cache是不可或缺的。因为无论是针对本地端的浏览器缓存,还是针...
最最最简单的C++缓存实现
在平常的后台开发中,通常中会用到缓存,一般会使用redis等内存数据库来实现,但是在很简单的程序中,其实没必要包含一些额外的依赖,通过C++的map即可实现。
0方式的 cpu_core/L1-dcache-load-misses/ 是36,246 , cpu_core/L1-dcache-load/ 是848,148,941,命中率为0.999957265。1方式的 cpu_core/L1-dcache-load-misses/ 是38,540 , cpu_core/L1-dcache-load/ 是848,192,764,命中率为0.999954562。所以我们写代码时应该多注意对齐、以及cache这些问题,感兴趣的同学还可以多试试不以64对齐的情况。
缓存的应用场景和范围十分广泛,下面给出其十分常见的两种应用背景:
首先,在操作系统内部,由于内存资源十分有限,而每个进程又都希望独享一块很大的内存空间。所以诞生了一种“虚拟内存”机制,它将进程的一部分内容暂留在磁盘中,在需要时再进行数据交换将其放入内存,这个过程就需要用到缓存算法机制进行置换。
其次,对于各类应用项目开发而言,在巨大的数据量面前,Catch 是不可或缺的。因为无论是针对本地端的浏览器缓存,还...
优化存储访问优化存储访问代码和数据缓存缓存组织一起使用的函数应该存储在一起一起使用的变量应该存储在一起数据对齐动态内存分配数据结构和容器类字符串顺序访问数据大数据结构中的cache冲突显式cache控制
优化存储访问
代码和数据缓存
缓存是主存的代理。缓存是为了以最快的可能访问最常用的数据。
缓存组织
大多数chache以行和集合的方式组织。cache机制的更多细节,参考(en.wikipedia.org/wiki/L2_cache)。
如果程序中包含很多变量和对象,它们又刚好分布在映射到相同cache的内
C++中可以采用stream读取文本文件,基本方式是一次一行,编程简洁易行,比用C方便多了。但是,凡事有利有弊,当文件行数较多时,文件读取IO次数就会随之增加,文件读取的时间会急剧增长。因为文件IO的时间要远大于CPU在内存中处理数据的时间,假如IO时间是毫秒级的,那么CPU在内存处理数据是纳秒级的。 很显然,C++中文本文件读取优化要解决的基本问题之一就是减少IO次数,最常用的