LRU Cache 设计与实现

原创 2015年07月08日 12:58:29

LRU 指的是 Least Recently Used 的缩写,中文名称叫做最近最少使用算法。是操作系统中常用的一种页面替换算法,在系统发生缺页中断时,置换未使用时间最长的页面。也常常用在 Cache 中,缓存最近使用过的数据。

数据结构

高效的实现 LRU 算法一般是使用哈希表 + 双链表,其中双链表用于缓存数据节点,并且其中的结点是按照最近被使用的时间排序的,每当一个数据节点被使用时或者一个新的数据节点加入时,需要将其放至表头位置。并且,当 Cache 已经满了时,此时如果一个新的数据结点加入到链表中时,需要替换掉最近最久使用的表尾位置的数据节点。

哈希表的作用是为了可以达到迅速找到某个结点,在没有哈希表的情况下,需要从链表中逐个遍历比较,时间复杂度为 O(n),在使用哈希表的情况下,可以使得我们可以在 O(1) 的时间找到需要访问的结点,或者返回未找到。

接口

Cache 的主要接口有

LRUCache(int capacity)
int get(int key)
void put(int key, int value)

LRU Cache 的主要接口有 构造函数 LRUCache 用于初始化一个容量为capacity 的缓存。get 用于从缓存中读出数据,并且需要将其放置开头位置,当缓存中没有所需的数据时,返回特殊值 -1。put 用于在缓存中加入一个新的数据。当加入一个新数据时,需要先检查缓存中是否已经存在与插入数据键值相同的数据以及容量是否已经满了。当缓存已存在键值相同的数据时,可以将其取出,修改节点的值,将其放置链表的开头并将其重新加入哈希表中。若缓存中不存在键值相同的数据时,先检查容量是否已满,在缓存容量已满的情况下,需要先去掉链表尾结点。并重新根据键值和数据生成一个新的结点放到链表的开头位置并加入哈希表中。

代码实现

完整的 Java 实现代码如下:

import java.util.*;

/**
 * 用带头节点和尾节点的双链表 + 哈希表 实现 LRU 缓存
 * Created by iprocoder on 15-5-24.
 */
public class LRUCache {

    /**
     * 缓存节点
     */
    private class CacheNode {

        int key;
        int value;
        CacheNode prev;
        CacheNode next;

        public CacheNode(int key, int value) {
            this.key = key;
            this.value = value;
        }

        public CacheNode() {
        }
    }

    private int capacity;
    private int num;
    private Map<Integer, CacheNode> map;
    private CacheNode head;
    private CacheNode tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.num = 0;
        this.map = new HashMap<>(capacity);
        this.head = new CacheNode();
        this.tail = new CacheNode();
        this.head.prev = null;
        this.head.next = tail;
        this.tail.prev = head;
        this.tail.next = null;
    }

    public int get(int key) {
        CacheNode cacheNode = map.get(key);

        if (cacheNode == null)
            return -1;
        detach(cacheNode);
        attach(cacheNode);
        return cacheNode.value;
    }

    public void set(int key, int value) {
        CacheNode cacheNode = map.get(key);
        if (cacheNode != null) {
            detach(cacheNode);
            cacheNode.value = value;
            attach(cacheNode);
        } else {
            if (num == capacity) {
                cacheNode = tail.prev;
                detach(cacheNode);
                map.remove(cacheNode.key);
            } else {
                num++;
                cacheNode = new CacheNode();
            }
            cacheNode.key = key;
            cacheNode.value = value;
            map.put(key, cacheNode);
            attach(cacheNode);
        }
    }

    /**
     * 分离节点
     * @param cacheNode
     */
    private void detach(CacheNode cacheNode) {
        cacheNode.prev.next = cacheNode.next;
        cacheNode.next.prev = cacheNode.prev;
    }

    /**
     * 将节点插入头部
     * @param cacheNode
     */
    private void attach(CacheNode cacheNode) {
        cacheNode.prev = head;
        cacheNode.next = head.next;
        head.next = cacheNode;
        cacheNode.next.prev = cacheNode;
    }

    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(1);
        lruCache.set(1, 3);
        System.out.println(lruCache.get(1));
        lruCache.set(3, 2);
        System.out.println(lruCache.get(2));
        System.out.println(lruCache.get(1));
    }
}

参考链接

http://www.hawstein.com/posts/lru-cache-impl.html

Written with StackEdit.

设计并实现一个LRU Cache

一、什么是Cache1 概念Cache,即高速缓存,是介于CPU和内存之间的高速小容量存储器。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近CPU的...
  • lisong694767315
  • lisong694767315
  • 2015年05月09日 15:17
  • 2775

【Leetcode】:LRU Cache_缓存淘汰算法LRU的设计与实现

内存淘汰算法是一个比较重要的算法,经常会被问道:如果让你设计一个LRU算法你会怎么做?尽可能的保持存取的高效。那么就依着这道算法题对LRU进行一个简单的介绍。...
  • lavorange
  • lavorange
  • 2014年12月10日 22:02
  • 1996

LRU Cache的简单c++实现

什么是 LRU LRU Cache是一个Cache的置换算法,含义是“最近最少使用”,把满足“最近最少使用”的数据从Cache中剔除出去,并且保证Cache中第一个数据是最近刚刚访问的,因为这样的数...
  • ygrx
  • ygrx
  • 2013年09月05日 09:17
  • 8092

设计并实现一个LRU Cache (java)

什么是Cache 概念 Cache,即高速缓存,是介于CPU和内存之间的高速小容量存储器。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近CPU的频率...
  • maoyeqiu
  • maoyeqiu
  • 2016年01月03日 22:37
  • 2055

LRU Cache 实现

LRU Cashe实现 LeetCode上有着样一道题目: Design and implement a data structure for Least Recently Used (LRU) ...
  • doufei_ccst
  • doufei_ccst
  • 2014年04月07日 11:58
  • 8200

LeetCode上一道经典的面试题-O(1)实现LRU Cache

你遇到过这个题吗? 实现一个LRU Cache。要求查询和插入都在O(1) 时间内完成。 遇到过?很正常。 没遇到?早晚会遇到。(鬼脸) 这是LeetCode上一道十分经典的题目,也是非常火的面试题。...
  • hxqneuq2012
  • hxqneuq2012
  • 2016年09月30日 11:04
  • 1288

LRU cache 算法的实现

#什么是LRU LRU Cache是一个Cache置换算法,含义是“最近最少使用”,当Cache满(没有空闲的cache块)时,把满足“最近最少使用”的数据从Cache中置换出去,并且保证Cache中...
  • renwotao2009
  • renwotao2009
  • 2016年11月07日 15:16
  • 1152

[leetcode] 146. LRU Cache 解题报告

题目链接: https://leetcode.com/problems/lru-cache/ Design and implement a data structure for Least Rec...
  • qq508618087
  • qq508618087
  • 2016年03月28日 04:48
  • 1580

如何设计实现一个LRU Cache?

1. 什么是LRU Cache? 之前,在LeetCode上看到一个LRU Cache实现的题目,题目描述是这样的: Design and implement a data struc...
  • xuchishao
  • xuchishao
  • 2015年09月08日 16:29
  • 543

使用C++实现一个LRU cache

什么是LRU Cache LRU是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。什么是Cache?狭义的Cache指的是位于CPU和主存间的快速RAM,...
  • yusiguyuan
  • yusiguyuan
  • 2014年09月28日 12:04
  • 1955
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:LRU Cache 设计与实现
举报原因:
原因补充:

(最多只允许输入30个字)