Redis与LRU实现

Redis中的LRU

Redis被当做缓存来使用,当你新增数据时,让它自动地回收旧数据是件很方便的事情。LRU 实际上是被唯一支持的数据移除方法。

实际中,redis并没有严格遵循LRU的思路去回收旧的数据,具体的redis关于LRU的实现,可以参考这篇文章https://www.cnblogs.com/houziwty/p/5129946.html

本次我们主要使用java实现LRU算法

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

实现思路:

对一个Cache的操作无非三种:插入(insert)、替换(replace)、查找(lookup)。
为了能够快速删除最久没有访问的数据项和插入最新的数据项,我们使用 双向链表 连接Cache中的数据项,并且保证链表维持数据项从最近访问到最旧访问的顺序。

  • 插入:当Cache未满时,新的数据项只需插到双链表头部即可。时间复杂度为O(1)O(1).
  • 替换:当Cache已满时,将新的数据项插到双链表头部,并删除双链表的尾结点即可。时间复杂度为O(1)O(1).
  • 查找:每次数据项被查询到时,都将此数据项移动到链表头部。

经过分析,我们知道使用双向链表可以保证插入和替换的时间复杂度是O(1)O(1),但查询的时间复杂度是O(n)O(n),因为需要对双链表进行遍历。为了让查找效率也达到O(1)O(1),很自然的会想到使用 hash table 。

0622f301add2bd8b85f65c04fbc6178467e.jpg

代码实现:

1.定义一个Node节点

public class Node {

    int key;
    int value;
    Node pre;
    Node next;


    public Node(int key, int value) {

        this.key = key;
        this.value = value;
    }

}

2.LRUCache.java

public class LRUCache {


    /**
     * 缓存大小
     */
    private int capacity;

    HashMap<Integer, Node> map = new HashMap<>();

    /**
     * 头结点
     */
    private Node head = null;

    /**
     * 尾节点
     */
    private Node end = null;

    /**
     * 初始化缓存大小
     */
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }

    /**
     * 删除节点
     */
    public void remove(Node node) {
        //需要注意变更pre,end指针情况
        if (node.pre != null) {
            node.pre.next = node.next;
        } else {
            head = node.next;
        }

        if (node.next != null) {
            node.next.pre = node.pre;
        } else {
            end = node.pre;
        }
    }

    /**
     * 设置头节点
     */
    public void setHead(Node node) {

        node.next = head;
        node.pre  =null;
        if (head != null) {
            head.pre = node;
        }

        head = node;

        //判断头尾是否为空
        if (end == null) {
            end = head;
        }
    }

    /**获取一个缓存数据后,应该把这个数据在当前位置删除掉,然后把它重新添加到头的位置
     * @param key
     * @return
     */
    public int get(int key) {

        if (map.containsKey(key)) {
            Node node = map.get(key);
            remove(node);
            setHead(node);

            return node.value;
        }
        return -1;
    }

    /**s设置指定位置的数据
     * @param key
     * @param value
     */
    public void set(int key, int value) {

        //如果该位置有元素,那么就替换数据,将其放入头结点
        if (map.containsKey(key)) {
            Node old = map.get(key);
            old.value = value;
            remove(old);
            setHead(old);
        } else {
            //如果是新的节点就要判断集合大小是否满足,并将新节点设置到头结点
            Node created = new Node(key, value);

            if (map.size()>=capacity) {
                map.remove(end.key);
                remove(end);
                setHead(created);
            } else {
                setHead(created);
            }
            map.put(key, created);
        }

    }
}

 

转载于:https://my.oschina.net/CentralD/blog/1833545

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值