zoukankan      html  css  js  c++  java
  • 【面试题】LRU算法及编码实现LRU策略缓存

    概念

      LRU(least recently used)就是将最近不被访问的数据给淘汰掉,LRU基于一种假设:认为最近使用过的数据将来被使用的概率也大,最近没有被访问的数据将来被使用的概率比较低。

    原理

      LRU一般通过链表形式来存放缓存数据,新插入或被访问的数据放在链表头部,超过一定阈值后,自动淘汰链表尾部的数据。下图很形象的说明了LRU缓存淘汰过程。(图片来自网络)

    步骤:

    1、新插入A, 将A放置在队列头部

    2、新插入B, 将B放置在队列头部, A自动推举次席。

    3、新插入C, 将C放置在队列头部, B自动推举次席。 

    4、新插入D, 将D放置在队列头部, C自动推举次席。 

    5、新插入E, 将E放置在队列头部, D自动推举次席。 

    6、新插入E, 将E放置在队列头部, 这时队列长度大于阈值,自动将尾部数据A给淘汰掉

    7、访问数据C,然后将C重新放置在队列头部。

    8、新插入E, 将E放置在队列头部, 这时队列长度大于阈值,自动淘汰尾部数据B

    编码实现LRU策略缓存

    /**
     * 2018/4/11.
     *
     * 使用链表+hashmap来实现, 这里没有考虑并发情况, 所以在代码中没有使用锁
     */
    public class LRUCache<K, V> {
    
        class CacheNode {
            public CacheNode before;
            public Object key;
            public Object value;
            public CacheNode after;
    
            public CacheNode() {
            }
        }
    
        private HashMap<K, CacheNode> caches;
        private int maxCapacity;
        private int currentCacheSize;
        /**
         * 头结点, 头结点不参与淘汰,只是作为标识链表中的第一个节点
         */
        private CacheNode head;
        /**
         * 尾节点, 尾节点不参与淘汰, 只是作为标识链表中最后一个节点
         */
        private CacheNode tail;
    
        public LRUCache(int maxCapacity) {
            this.maxCapacity = maxCapacity;
            caches = new HashMap<>(maxCapacity);
            head = tail = new CacheNode();
            head.after = tail; //对head 的after节点赋值, 防止后续操作出现空指针异常
            tail.before = head; // 对tail的before节点赋值, 防止后续操作出现空指针异常
        }
    
        public void put(K k, V v) {
            CacheNode node = caches.get(k);
            if (node == null) {
                if (currentCacheSize >= maxCapacity) {
                    caches.remove(tail.before.key); //淘汰尾部的元素
                    removeLast();
                }
    
                node = new CacheNode();
                node.key = k;
    
                currentCacheSize ++;
            }
    
            node.value = v;
            moveToFirst(node); // LRU策略, 新插入的元素放置到队列头部
            caches.put(k, node);
        }
    
        public void moveToFirst(CacheNode node) {
            CacheNode n = head.after;
            head.after = node;
            node.before = head;
            n.before = node;
            node.after = n;
        }
    
        public void removeLast() {
            CacheNode n = tail.before.before;
            n.after = tail;
            tail.before = n;
        }
    
        public Object get(K k) {
            CacheNode node = caches.get(k);
            if (node == null) {
                return null;
            }
    
            Object v = node.value;
            moveToFirst(node);
            return v;
        }
    
        public Object remove(K k) {
            CacheNode node = caches.get(k);
            if (node == null) {
                return null;
            }
    
            CacheNode pre = node.before;
            CacheNode next = node.after;
            pre.after = next;
            next.before = pre;
    
            caches.remove(k);
    
            currentCacheSize --;
            return node.value;
        }
    }

    上述代码在博主本机测试验证通过(单线程操作下)

  • 相关阅读:
    2009中国IT界名人
    jQuery简介
    Spring下载地址
    ContextLoaderListener
    MyBatisUtil类
    SSM事务
    后台管理中心跳转问题解决
    mybatis返回boolean值时数据库返回null
    yarn作业提交过程
    Hadoop集群运行wordcount jar包出错
  • 原文地址:https://www.cnblogs.com/jsnr-tdyd/p/8800649.html
Copyright © 2011-2022 走看看