请你谈谈利用LinkedHashMap实现LRU算法缓存

1key和value都允许为空;2key重复会覆盖,value可以重复;3有序的;4LinkedHashMap是非线程安全的;

1 LinkedHashMap可以认为是HashMap+LinkedList,也就是说,它使用HashMap操作数据结构,也用LinkedList维护插入元素的先后顺序. 2 LinkedHashMap的实现思想就是多态,理解LinkedHashMap能帮助我们加深对多态的理解.

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>

而它比HashMap多了两个属性:

//链表的头结点
private transient Entry<K,V> header;
//该属性指取得键值对的方式,是个布尔值:false表示插入顺序;true表示访问顺序;
private final boolean accessOrder;

LinkedHashMap有五个构造器:

   	//用默认的初始容量和负载因子构建一个LinkedHashMap,取出键值对的方式是插入顺序
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    //构造一个指定初始容量的LinkedHashMap,取得键值对的顺序
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    //构造一个指定初始容量和负载因子,按照插入顺序的LinkedHashMap
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

    //根据给定的初始容量,负载因子和键值对迭代顺序构建一个LinkedHashMap
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

    //通过给定的map创建一个LinkedHashMap,负载因子是默认值,迭代方式是插入顺序.
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super(m);
        accessOrder = false;
    }

从构造方法可以看出,默认都是采用插入顺序来维持取出键值对的次序.所有的构造方法都是通过父类的构造方法来建造对象的.

LinkedHashMap和HashMap的区别在于他们的基本数据机构上,我们来看一下LinkedHashMap的基本数据结构Entry:

  private static class Entry<K,V> extends HashMap.Entry<K,V> {
        // These fields comprise the doubly linked list used for iteration.
        Entry<K,V> before, after;

        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
            super(hash, key, value, next);
        }

next是用于维护HashMap指定table位置上连接的Entry顺序的;before、after是用于维护Entry插入的先后顺序的.正是因为before、after和header的存在,LinkedHashMap才形成了循环双向链表.需要注意的是,header节点,是LinkedHashMap的一个属性,它并不保存key-value内容,它是双向链表的入口.

利用LinkedHashMap实现LRU算法缓存

所谓LRU:Least Recently Used,最近最少使用,即当缓存了,会优先淘汰那些最近不常访问的数据.即冷数据优先淘汰.
我们来看看LinkedHashMap的一个构造方法:

    //根据给定的初始容量,负载因子和键值对迭代顺序构建一个LinkedHashMap
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

在这个构造方法中,有个accessOrder,它不同的值有不同的意义:
false, 所有的Entry按照插入的顺序排列
true, 所有的Entry按照访问的顺序排列

访问的顺序:如果有1 2 3这3个Entry,那么访问了1,就把1移到尾部去,即2 3 1。每次访问都把访问的那个数据移到双向队列的尾部去,那么每次要淘汰数据的时候,双向队列最头的那个数据不就是最不常访问的那个数据了吗?换句话说,双向链表最头的那个数据就是要淘汰的数据。

import java.util.*;


public class Solution {
    /**
     * lru design
     * @param operators int整型二维数组 the ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
     public int[] LRU (int[][] operators, int k) {
        // write code here
        ArrayList<Integer> list = new ArrayList<>();
        LRUCache lru = new LRUCache(k);
        for(int[] opt:operators){
            if(opt[0] == 1){
                lru.put(opt[1],opt[2]);
            }else{
                list.add(lru.get(opt[1]));
            }
        }
        int[] res = new int[list.size()];
        int i = 0;
        for(int val:list){
            res[i] = list.get(i);
            i++;
        }
        return res;
    }
}
 
//设置LRU缓存结构
class LRUCache{
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
     
    public LRUCache(int capactity){
        this.cap = capactity;
    }
     
    // 将key变为最近使用
    private void makeRecently(int key){
        int val = cache.get(key);
        //删除key,重新插入到队尾
        cache.remove(key);
        cache.put(key, val);
    }
     
     
    //获取值
    public int get(int key){
        if(!cache.containsKey(key)){
            return -1;
        }
        //将这个key变为最近使用的
        makeRecently(key);
        return cache.get(key);
    }
     
    //存进值
    public void put(int key,int val){
        if(cache.containsKey(key)){
            cache.put(key, val);
            //设置为最近使用
            makeRecently(key);
            return;
        }
         
        //超出缓存的大小
        if(cache.size() >= this.cap){
            //拿到链表头部的key(其最久未使用的key)
            int oldstKet = cache.keySet().iterator().next();
            cache.remove(oldstKet);
        }
        //将新的key添加到链表尾部
        cache.put(key,val);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值