LRU算法简介
LRU是什么?
按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常注明的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。
1.2:小王的困惑
当小王看到LRU的时候,瞬间感觉抓住了救命稻草,这个算法不是就完全契合产品的需求吗?只要把用户数据按照LRU去筛选,利用数据结构完成的事情,完全减少了自己存储、添加字段判断、排序的过程,这样对于提高服务器性能肯定有很大的帮助,岂不美哉!小王考虑好之后,就决定先写一个demo来实现LRU,那么在php中是如何实现LRU呢?考虑了许久。以上内容来自互联网 直接 上代码
<?php
require_once('PHPUnit/Autoload.php');
require_once(dirname(__FILE__).'/../src/LRUCache/LRUCache.php'); class LRUCacheTest extends PHPUnit_Framework_TestCase { public function testStartsEmpty() {
$lru = new \LRUCache\LRUCache(1000);
$this->assertNull($lru->get(1));
} public function testGet() {
$lru = new \LRUCache\LRUCache(1000);
$key = 'key1';
$data = 'content for key1';
$lru->put($key, $data);
$this->assertEquals($lru->get($key), $data);
} public function testMultipleGet() {
$lru = new \LRUCache\LRUCache(1000);
$key = 'key1';
$data = 'content for key1';
$key2 = 'key2';
$data2 = 'content for key2'; $lru->put($key, $data);
$lru->put($key2, $data2); $this->assertEquals($lru->get($key), $data);
$this->assertEquals($lru->get($key2), $data2);
} public function testPut() {
$numEntries = 1000;
$lru = new \LRUCache\LRUCache($numEntries); $key1 = 'mykey1';
$value1 = 'myvaluefromkey1'; $lru->put($key1, $value1);
$this->assertEquals($lru->get($key1), $value1);
} public function testMassivePut() {
$numEntries = 90000;
$lru = new \LRUCache\LRUCache($numEntries); while($numEntries > 0) {
$lru->put($numEntries - 899999, 'some value...');
$numEntries--;
}
} public function testRemove() {
$numEntries = 3;
$lru = new \LRUCache\LRUCache($numEntries); $lru->put('key1', 'value1');
$lru->put('key2', 'value2');
$lru->put('key3', 'value3'); $ret = $lru->remove('key2');
$this->assertTrue($ret); $this->assertNull($lru->get('key2')); // test remove of already removed key
$ret = $lru->remove('key2');
$this->assertFalse($ret); // make sure no side effects took place
$this->assertEquals($lru->get('key1'), 'value1');
$this->assertEquals($lru->get('key3'), 'value3');
} public function testPutWhenFull() {
$lru = new \LRUCache\LRUCache(3); $key1 = 'key1';
$value1 = 'value1forkey1';
$key2 = 'key2';
$value2 = 'value2forkey2';
$key3 = 'key3';
$value3 = 'value3forkey3';
$key4 = 'key4';
$value4 = 'value4forkey4'; // fill the cache
$lru->put($key1, $value1);
$lru->put($key2, $value2);
$lru->put($key3, $value3); // access some elements more often
$lru->get($key2);
$lru->get($key2);
$lru->get($key3); // put a new entry to force cache to discard the oldest
$lru->put($key4, $value4); $this->assertNull($lru->get($key1));
}
}
<?php namespace LRUCache; /**
* Class that implements the concept of an LRU Cache
* using an associative array as a naive hashmap, and a doubly linked list
* to control the access and insertion order.
*
* @author Rogério Vicente
* @license MIT (see the LICENSE file for details)
*/
class LRUCache { // object Node representing the head of the list
private $head; // object Node representing the tail of the list
private $tail; // int the max number of elements the cache supports
private $capacity; // Array representing a naive hashmap (TODO needs to pass the key through a hash function)
private $hashmap; /**
* @param int $capacity the max number of elements the cache allows
*/
public function __construct($capacity) {
$this->capacity = $capacity;
$this->hashmap = array();
$this->head = new Node(null, null);
$this->tail = new Node(null, null); $this->head->setNext($this->tail);
$this->tail->setPrevious($this->head);
} /**
* Get an element with the given key
* @param string $key the key of the element to be retrieved
* @return mixed the content of the element to be retrieved
*/
public function get($key) { if (!isset($this->hashmap[$key])) { return null; } $node = $this->hashmap[$key];
if (count($this->hashmap) == 1) { return $node->getData(); } // refresh the access
$this->detach($node);
$this->attach($this->head, $node); return $node->getData();
} /**
* Inserts a new element into the cache
* @param string $key the key of the new element
* @param string $data the content of the new element
* @return boolean true on success, false if cache has zero capacity
*/
public function put($key, $data) {
if ($this->capacity <= 0) { return false; }
if (isset($this->hashmap[$key]) && !empty($this->hashmap[$key])) {
$node = $this->hashmap[$key];
// update data
$this->detach($node);
$this->attach($this->head, $node);
$node->setData($data);
}
else {
$node = new Node($key, $data);
$this->hashmap[$key] = $node;
$this->attach($this->head, $node); // check if cache is full
if (count($this->hashmap) > $this->capacity) {
// we're full, remove the tail
$nodeToRemove = $this->tail->getPrevious();
$this->detach($nodeToRemove);
unset($this->hashmap[$nodeToRemove->getKey()]);
}
}
return true;
} /**
* Removes a key from the cache
* @param string $key key to remove
* @return bool true if removed, false if not found
*/
public function remove($key) {
if (!isset($this->hashmap[$key])) { return false; }
$nodeToRemove = $this->hashmap[$key];
$this->detach($nodeToRemove);
unset($this->hashmap[$nodeToRemove->getKey()]);
return true;
} /**
* Adds a node to the head of the list
* @param Node $head the node object that represents the head of the list
* @param Node $node the node to move to the head of the list
*/
private function attach($head, $node) {
$node->setPrevious($head);
$node->setNext($head->getNext());
$node->getNext()->setPrevious($node);
$node->getPrevious()->setNext($node);
} /**
* Removes a node from the list
* @param Node $node the node to remove from the list
*/
private function detach($node) {
$node->getPrevious()->setNext($node->getNext());
$node->getNext()->setPrevious($node->getPrevious());
} } /**
* Class that represents a node in a doubly linked list
*/
class Node { /**
* the key of the node, this might seem reduntant,
* but without this duplication, we don't have a fast way
* to retrieve the key of a node when we wan't to remove it
* from the hashmap.
*/
private $key; // the content of the node
private $data; // the next node
private $next; // the previous node
private $previous; /**
* @param string $key the key of the node
* @param string $data the content of the node
*/
public function __construct($key, $data) {
$this->key = $key;
$this->data = $data;
} /**
* Sets a new value for the node data
* @param string the new content of the node
*/
public function setData($data) {
$this->data = $data;
} /**
* Sets a node as the next node
* @param Node $next the next node
*/
public function setNext($next) {
$this->next = $next;
} /**
* Sets a node as the previous node
* @param Node $previous the previous node
*/
public function setPrevious($previous) {
$this->previous = $previous;
} /**
* Returns the node key
* @return string the key of the node
*/
public function getKey() {
return $this->key;
} /**
* Returns the node data
* @return mixed the content of the node
*/
public function getData() {
return $this->data;
} /**
* Returns the next node
* @return Node the next node of the node
*/
public function getNext() {
return $this->next;
} /**
* Returns the previous node
* @return Node the previous node of the node
*/
public function getPrevious() {
return $this->previous;
} }
以上代码仅供大家参考
LRU算法简介的更多相关文章
- Java实现LRU算法
一.LRU算法简介 LRU(Least Recently Used)最近最久未使用算法 常见应用场景:内存管理中的页面置换算法.缓存淘汰中的淘汰策略等 二.实现理论 底层结构:双向链表 + HashM ...
- mysql 原理 ~ LRU 算法与buffer_pool
一 简介:针对查询和事务的页在内存中的处理,是如何进行的 二 LRU算法 普通 : 实现的是末尾淘汰法,当整个链表已满时,淘汰尾部,将新的数据页加入头部 mysql_lru改进 : 分为两部分 yan ...
- Guava---缓存之LRU算法
随笔 - 169 文章 - 0 评论 - 292 GuavaCache学习笔记一:自定义LRU算法的缓存实现 前言 今天在看GuavaCache缓存相关的源码,这里想到先自己手动实现一个LRU ...
- LRU算法介绍和在JAVA的实现及源码分析
一.写随笔的原因:最近准备去朋友公司面试,他说让我看一下LRU算法,就此整理一下,方便以后的复习. 二.具体的内容: 1.简介: LRU是Least Recently Used的缩写,即最近最少使用. ...
- Android图片缓存之Lru算法
前言: 上篇我们总结了Bitmap的处理,同时对比了各种处理的效率以及对内存占用大小.我们得知一个应用如果使用大量图片就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发 ...
- 缓存淘汰算法--LRU算法
1. LRU1.1. 原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是"如果数据最近被访问过,那么将来被访问的几率也 ...
- 借助LinkedHashMap实现基于LRU算法缓存
一.LRU算法介绍 LRU(Least Recently Used)最近最少使用算法,是用在操作系统中的页面置换算法,因为内存空间是有限的,不可能把所有东西都放进来,所以就必须要有所取舍,我们应该把什 ...
- LinkedHashMap实现LRU算法
LinkedHashMap特别有意思,它不仅仅是在HashMap上增加Entry的双向链接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式创建LinkedHashMap) ...
- LinkedHashMap 和 LRU算法实现
个人觉得LinkedHashMap 存在的意义就是为了实现 LRU 算法. public class LinkedHashMap<K,V> extends HashMap<K,V&g ...
随机推荐
- c++ 容器反转
// reverse algorithm example #include <iostream> // std::cout #include <algorithm> // st ...
- springboot+mybatis+druid+sqlite/mysql/oracle
搭建springboot+mybatis+druid+sqlite/mysql/oracle附带测试 1.版本 springboot2.1.6 jdk1.8 2.最简springboot环境 http ...
- CF1214B
CF1214B 解法: 暴力枚举,时间复杂度 $ O(n) $ CODE: #include<iostream> #include<cstdio> #include<cs ...
- RAFT选举算法-分布式数据库困惑
在做HIS研发工作的时候一直想完善其数据组件,想做一个分布式的数据库支持系统.但一直以来都不清楚这个选举算法应怎么做,原来有一个叫raft的算法https://www.cnblogs.com/just ...
- 关于mysql数据库远程访问
mysql数据库安装默认为只能本地访问,若需远程连接需根据不同的操作系统做一些操作 Windows: 新装的mysql本地无法登录,显示为1045错误 mysql#1045(1045Access de ...
- Xshell登录Vagrant方式
Xshell登录Vagrant方式 我上一篇文章 介绍了vagrant 如何创建虚拟机集群,在上篇文章的基础上,用xshell 登录 虚拟机发现 默认是无法使用账号密码登录root账号,只能使用vag ...
- Swift 条件语句
条件语句通过设定的一个或多个条件来执行程序,在条件为真时执行指定的语句,在条件为 false 时执行另外指定的语句. 可以通过下图来简单了解条件语句的执行过程: Swift 提供了以下几种类型的条件语 ...
- Swiper轮播插件使用
前文 Swiper是纯javascript打造的滑动特效插件,面向手机.平板电脑等移动终端,能实现触屏焦点图.触屏Tab切换.触屏多图切换等常用效果. 归根到此,Swi ...
- BAPI_GOODSMVT_CREATE物料凭证增强字段
项目MSEG 的 BAPI 表增强结构 BAPI_TE_XMSEG 抬头MKPF 的 BAIP 表增强 BAPI_TE_XMKPF 1. 在结构BAPI_TE_XMSEG中appending str ...
- Java使用Java OCR API进行验证码识别
Maven坐标: <!-- https://mvnrepository.com/artifact/com.asprise.ocr/java-ocr-api --> <dependen ...