lru实现

最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
https://www.cnblogs.com/kyoner/p/11179766.html
在这里插入图片描述
1、新数据插入到链表头部;
2、每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
3、当链表满的时候,将链表尾部的数据丢弃。
【命中率】
当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。
【复杂度】
实现简单。
【代价】
命中时需要遍历链表,找到命中的数据块索引,然后需要将数据移到头部。该算法的时间复杂度为O(n),显然不是最优的算法,那么有没有算法,可以达到O(1),当然是有的,早早的计算机科学家已经想到,并且已经实现了。

之前使用双向链表去实现LRU算法时,时间复杂度没有达到O(1),主要原因在于遍历结点时,带来的时间开销,那么换句话说,要实现遍历结点时,时间复杂度为O(1),第一时间想到的应该是hash数组,但是hash算法可能会存在不同的key值,产生相同的hash值,那么可以将不同key,但是相同hash值的结点,以单链表的形式存放。这样仅仅是实现了存取时间复杂度为O(1),如何实现数据能够按访问顺序存放呢?并且增删的时间复杂度为O(1),这个可以使用双向链表来实现。

所以综合来讲,就是实现散列数组+双向链表来使用LRU,可以达到时间复杂度为O(1)
在这里插入图片描述
在这里插入图片描述

java代码实现:leetcode146 - lru

import java.util.HashMap;
public class LRUCache{
    //节点定义
    class Node{
        int key;
        int val;
        Node next;
        Node prev;
        public Node(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }
    //容量
    HashMap<Integer,Node> map;
    Node head;
    Node tail;
    private int capacity;
    int size;

    public LRUCache(int capacity) {
        head=new Node(0,0);
        tail=new Node(0,0);
        head.next=tail;
        tail.prev=head;
        this.capacity = capacity;
        map=new HashMap<>();
        size=0;
    }
    /**
     * 获取数据
     * @param key
     * @return
     */
    public int get(int key){
        //情况一:如果数据是不存在的
        if (!map.containsKey(key)){
            return -1;
        }
        //情况二:数据存在
        //1.获取数据
        Node node = map.get(key);
        //2.把数据放到链表头
        remove(key);
        addHead(key,node.val);
        return node.val;
    }
    /**
     * 存放数据
     * @param key
     * @return
     */
    public void put(int key,int val){
        Node node=new Node(key,val);
        //情况一:如果数据已经存在
        if (map.containsKey(key)){
            //在链表中删除该node节点
            remove(key);
            //把数据放到链表头上
            addHead(key,node.val);
        }
        //情况二:如果数据不存在
        else {
            //把数据放到链表头上
            addHead(key,node.val);
        }
    }

    public void remove(int key){
        Node cur = map.get(key);
        Node next = cur.next;
        Node prev = cur.prev;
        prev.next=next;
        next.prev=prev;
        size--;
        map.remove(key);
    }
    public void addHead(int key,int val){
        Node node =new Node(key,val);
        Node next = head.next;
        head.next=node;
        node.next=next;
        next.prev=node;
        node.prev=head;
        size++;
        map.put(key,node);
        if (size>capacity){
            Node preTail = tail.prev;
            remove(preTail.key);
        }
    }
    //    public static void main(String[] args) {
//        Solution cache=new Solution(3);
//        cache.put(1, 1);
//        cache.put(2, 2);
//        cache.put(3, 3);
//        System.out.println("first entry: "+cache.head.next.key);
//        cache.print((HashMap<Integer, Node>) cache.map);
//        cache.put(4, 4);
//        System.out.println("============================");
//        System.out.println("first entry: "+cache.head.next.key);
//        cache.print((HashMap<Integer, Node>) cache.map);
//        cache.put(5, 5);
//        System.out.println("============================");
//        System.out.println("first entry: "+cache.head.next.key);
//        cache.print((HashMap<Integer, Node>) cache.map);
//    }
}

牛客网LRU题:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Solution {
    Map<Integer,Node> map;
    int capacity;
    int size;
    Node head;
    Node tail;
     {
        map=new HashMap();
        size=0;
        head=new Node(0,0);
        tail=new Node(0,0);
        head.next=tail;
        tail.pre=head;
    }
    public int get(int key){
        //元素不存在
        if (!map.containsKey(key)){
            return -1;
        }
        //元素存在
        Node node = map.get(key);
        //先删除元素
        remove(node);
        //在把元素放到链表头
        addToHead(node);
        return node.val;
    }
    public void put(int key,int val){
        Node node = new Node(key, val);
        //元素已经存在
        if (map.containsKey(key)){
            //先删除元素
            remove(node);
            //在把元素放到链表头
            addToHead(node);
        }
        //元素不存在
        //在把元素放到链表头
        addToHead(node);
    }
    private void remove(Node node) {
        Node pre = node.pre;
        Node next = node.next;
        pre.next=next;
        next.pre=pre;
        size--;
        //todo 忘记删映射关系...记得加上!!
        map.remove(node.key);
    }
    private void addToHead(Node node) {
        //先判断是否以及满了
        if (size==capacity){
            //满了,移除最后一个元素
            Node pre = tail.pre;
            remove(pre);
        }
        //没满
        //把此刻的头节点的下一个节点存起来,因为接下来head.next会改变
        Node next = head.next;
        head.next=node;
        node.next=next;
        next.pre=node;
        node.pre=head;
        size++;
        map.put(node.key,node);
    }
    class Node{
        int key;
        int val;
        Node pre;
        Node next;
        public Node(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }
    /**
     * lru design
     * @param operators int整型二维数组 the ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public static int[] LRU(int[][] operators, int k) {
        // write code here
        Solution solution = new Solution();
        solution.capacity=k;
        //结果数组
        int count = (int) Arrays.stream(operators).filter(operator-> operator[0] == 2).count();
        int[] result=new int[count];

        int length = operators.length;
        for (int i = 0,j=0; i < length; i++) {
            int[] operator = operators[i];
            if (operator[0]==1){
                solution.put(operator[1],operator[2]);
            }
            if (operator[0]==2){
                int i1 = solution.get(operator[1]);
                result[j++]=i1;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[][] i=new int[][]{{1, 1, 1}, {1, 2,2}, {1, 3, 2},{2,1},{1,4,4},{2,2}};

        int[] lru = LRU(i, 3);

        System.out.println(Arrays.toString(lru));
    }

    //    public void print(HashMap<Integer, Node> map){
//        Collection<Node> entry=map.values();
//        Iterator it=entry.iterator();
//        while(it.hasNext()){
//            Node e=(Node) it.next();
//            System.out.println(e.key+"  :  "+e.val);
//        }
//    }
//
//    public static void main(String[] args) {
//        Solution cache=new Solution(3);
//        cache.put(1, 1);
//        cache.put(2, 2);
//        cache.put(3, 3);
//        System.out.println("first entry: "+cache.head.next.key);
//        cache.print((HashMap<Integer, Node>) cache.map);
//        cache.put(4, 4);
//        System.out.println("============================");
//        System.out.println("first entry: "+cache.head.next.key);
//        cache.print((HashMap<Integer, Node>) cache.map);
//        cache.put(5, 5);
//        System.out.println("============================");
//        System.out.println("first entry: "+cache.head.next.key);
//        cache.print((HashMap<Integer, Node>) cache.map);
//    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值