题目来源

LeetCode: https://leetcode.com/problems/lru-cache/

LRU简介

LRU (Least Recently Used,最近最少使用)算法是操作系统中一种经典的页面置换算法,当发生缺页中断时,需要将内存的一个或几个页面换出,LRU指出应该将内存最近最少使用的那些页面进行换出,依据的是程序的局部性原理,最近经常使用的页面在不久的将来也很有可能被使用,反之最近很少使用的页面未来也不太可能再使用。

LRU 数据结构

LRU采用双向链表+hash表的数据结构实现,双向链表作为队列存储当前缓存节点,其中从表头到表尾的元素按照最近使用的时间进行排列,放在表头的是最近刚刚被使用过的元素,表尾的最近最少使用的元素;如果仅仅采用双向链表,那么查询某个元素需要 O(n) 的时间,为了加快双向链表中元素的查询速度,采用hash表讲key进行映射,可以在O(1)的时间内找到需要节点。

LRU主要实现以下两个接口:

int Get(int key);
void Put(int key, int value);

其中 Get 用来读取队列中的元素,同时需要将该元素移动到表头;Put 用来向队列中插入元素。

LRU 具体实现

从实现的角度来看,每次 Get 时, 需要判断该 key 是否在队列中,如果不在,返回-1;如果在,需要重新移动该元素到表头位置(具体实现,可以先删除,在插入到表头)。 每次 Put 时,首先需要判断key是否在队列中,如果在,那么更新其 value值,然后移动该元素到表头即可;如果不在,需要进一步判断,队列是否已满,如果已满;那么需要首先删除队尾元素,并对 size - 1, 删除哈希表中对应元素的 key;然后在插入新的元素到队头。

具体C++代码如下:

 /**
* LRU Cache Implementation using DoubleLinkList & hashtable
* Copyright 2015 python27
* 2015/06/26
*/
#include <iostream>
#include <string>
#include <map>
#include <list>
#include <deque>
#include <cassert>
#include <cstdio>
#include <cstdlib>
using namespace std; struct CacheNode
{
int key;
int value;
CacheNode* prev;
CacheNode* next; CacheNode(int k, int v) : key(k), value(v), prev(NULL), next(NULL)
{} CacheNode():key(), value(), prev(NULL), next(NULL)
{}
}; class LRUCache
{
public:
LRUCache(int capacity); int Get(int key);
void Put(int key, int value); public:
void PrintList() const;
private:
void InsertNodeFront(CacheNode* p);
void DeleteNode(CacheNode* p); private:
map<int, CacheNode*> m_hashtable; // hash table
CacheNode* m_head; // double link list head
CacheNode* m_tail; // double link list tail
int m_capacity; // capacity of link list
int m_size; // current size of link list
}; void LRUCache::PrintList() const
{
CacheNode* p = m_head;
for (p = m_head; p != NULL; p = p->next)
{
printf("(%d, %d)->", p->key, p->value);
}
printf("\n");
printf("size = %d\n", m_size);
printf("capacity = %d\n", m_capacity);
} LRUCache::LRUCache(int capacity)
{
m_capacity = capacity;
m_size = ;
m_head = NULL;
m_tail = NULL;
} // insert node into head pointed by p
void LRUCache::InsertNodeFront(CacheNode* p)
{
if (p == NULL) return; if (m_head == NULL)
{
m_head = p;
m_tail = p;
}
else
{
p->next = m_head;
m_head->prev = p;
m_head = p;
}
} // delete node in double linklist pointed by p
void LRUCache::DeleteNode(CacheNode* p)
{
if (p == NULL) return; assert(m_head != NULL && m_tail != NULL); if (m_size == )
{
if (p == m_head && p == m_tail)
{
delete p;
m_head = NULL;
m_tail = NULL;
}
else
{
fprintf(stderr, "Delete Wrong! No such Node");
return;
}
}
else if (p == m_head)
{
m_head = m_head->next;
m_head->prev = NULL;
delete p;
}
else if (p == m_tail)
{
m_tail = m_tail->prev;
m_tail->next = NULL;
delete p;
}
else
{
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
} } int LRUCache::Get(int key)
{
// if key not in return -1
if (m_hashtable.find(key) == m_hashtable.end())
{
return -;
} CacheNode* p = m_hashtable[key];
int k = p->key;
int v = p->value; // delete this node
DeleteNode(p); // insert this node to the head
p = new CacheNode(k, v);
InsertNodeFront(p);
// update hash table
m_hashtable[k] = p;
return p->value;
} void LRUCache::Put(int key, int value)
{
// if key alread in, update
if (m_hashtable.find(key) != m_hashtable.end())
{
CacheNode* p = m_hashtable[key]; // delete node
DeleteNode(p);
// insert node
p = new CacheNode(key, value);
InsertNodeFront(p);
// update hash table
m_hashtable[key] = p;
return;
}
// if list is full, delete the tail node
else if (m_size >= m_capacity)
{
// delete the tail node
CacheNode* p = m_tail;
m_hashtable.erase(p->key);
DeleteNode(p);
m_size--;
} // create node and insert into head
assert(m_size < m_capacity);
CacheNode* p = new CacheNode(key, value);
InsertNodeFront(p);
m_hashtable[key] = p;
m_size++;
} int main()
{
LRUCache lru();
lru.Put(, );
lru.PrintList();
lru.Put(, );
lru.PrintList();
lru.Put(, );
lru.PrintList();
lru.Put(, );
lru.PrintList();
int value = lru.Get();
printf("Get(3) = %d\n", value);
lru.PrintList();
value = lru.Get();
printf("Get(2) = %d\n", value);
lru.PrintList();
value = lru.Get();
printf("Get(4) = %d\n", value);
lru.PrintList();
value = lru.Get();
printf("Get(1) = %d\n", value);
lru.PrintList(); return ;
}

【算法33】LRU算法的更多相关文章

  1. 【算法】—— LRU算法

    LRU原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”. 实现1 最常见的 ...

  2. 【算法】LRU算法

    缓存一般存放的都是热点数据,而热点数据又是利用LRU(最近最久未用算法)对不断访问的数据筛选淘汰出来的. 出于对这个算法的好奇就查了下资料. LRU算法四种实现方式介绍 缓存淘汰算法 利用Linked ...

  3. Redis内存管理中的LRU算法

    在讨论Redis内存管理中的LRU算法之前,先简单说一下LRU算法: LRU算法:即Least Recently Used,表示最近最少使用页面置换算法.是为虚拟页式存储管理服务的,是根据页面调入内存 ...

  4. LRU 算法

    LRU算法 很多Cache都支持LRU(Least Recently Used)算法,LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定 ...

  5. Redis内存回收:LRU算法

    Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read Redis中采用两种算法进行内存回收,引用计数算法以及LRU ...

  6. LRU算法原理解析

    LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的. 现代操作系统提供了一种对主存的抽象概念虚拟内存,来对主存进行更好地管理.他将主存 ...

  7. 二叉树遍历问题、时间空间复杂度、淘汰策略算法、lru数据结构、动态规划贪心算法

    二叉树的前序遍历.中序遍历.后序遍历 前序遍历 遍历顺序规则为[根左右] ABCDEFGHK 中序遍历 遍历顺序规则为[左根右] BDCAEHGKF 后序遍历 遍历顺序规则为[左右根] DCBHKGF ...

  8. LRU算法详解

    一.什么是 LRU 算法 就是一种缓存淘汰策略. 计算机的缓存容量有限,如果缓存满了就要删除一些内容,给新内容腾位置.但问题是,删除哪些内容呢?我们肯定希望删掉哪些没什么用的缓存,而把有用的数据继续留 ...

  9. Redis 为何使用近似 LRU 算法淘汰数据,而不是真实 LRU?

    在<Redis 数据缓存满了怎么办?>我们知道 Redis 缓存满了之后能通过淘汰策略删除数据腾出空间给新数据. 淘汰策略如下所示: 设置过期时间的 key volatile-ttl.vo ...

  10. 缓存淘汰算法--LRU算法

    1. LRU1.1. 原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是"如果数据最近被访问过,那么将来被访问的几率也 ...

随机推荐

  1. Python 列表表达式 ,迭代器(2) Yield

    .yield 暂存为list def max_generator(numbers): current_max = for i in numbers: current_max = max(i, curr ...

  2. Express 应用生成器

    [Express 应用生成器] 通过应用生成器工具 express 可以快速创建一个应用的骨架. 通过如下命令安装,-g意味着安装在全局目录下: 下面的示例就是在当前工作目录下创建一个命名为 myap ...

  3. jquery 显示 隐藏

    参考 http://www.w3school.com.cn/jquery/jquery_hide_show.asp $("#a").hide(); $("#a" ...

  4. hibernate经常报的几个不起眼的错误, 都是因为不细心或者手滑了输入有误造成了

    最近会经常用到hibernate了, 也经常报错, 看着屏幕上一根大红条是非常不爽的, 这几天集合了一下经常报的错误, 整合一下放到这里, 以后再出现这个错误直接去解决就好了 1, org.hiber ...

  5. Element div is not closed

    报错内容:Element div is not closed 解决方法: 将代码复制到NotePad++.SubLime Text等文本编辑器中,另存为.jsp或者.html文件. 这样可以利用语法高 ...

  6. string类小结

    要想使用标准C++中string类,必须要包含 #include <string>// 注意是<string>,不是<string.h>,带.h的是C语言中的头文件 ...

  7. 'wmic' 不是内部或外部命令,也不是可运行的程序 解决方法

    在环境变量中查看变量名Path下的变量值是否有以下讯息? 如没有复制(Ctrl+C).黏贴(Ctrl+V)→确定即可. %SystemRoot%;%SystemRoot%\system32;%Syst ...

  8. [leetcode]689. Maximum Sum of 3 Non-Overlapping Subarrays三个非重叠子数组的最大和

    In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum. E ...

  9. 8-组成n的1的个数

    /*                                             ones时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述    Given a ...

  10. handler通信机制

    package com.example.gp08_day26_handler3; import android.os.Bundle; import android.os.Handler; import ...