HashMap实现LRU(最近最少使用)缓存更新算法

最近阿里巴巴电话面试被问到了如何使用固定容量的HashMap,实现LRU算法。当时一脸懵逼,平时用HashMap也就用来快速存取数据而已,容量都是不限的。

想了半天,想到对node节点进行扩展,加入引用计数,然后到达指定容量后,删除引用计数最少的。
面试官质疑这样效率太低了,能不能优化下。
想到删除时,需要遍历所有元素,代价为O(n),太大了。想到可以用最小堆来进行筛选。被问到建堆的节点值是什么,这块没想好,卡壳了。

面试完之后,网上搜了下,才发现Java官方已经替我们预留了LRU算法的框架,在LinkedHashMap里。我们只需要扩展下即可,代码示例如下:

/**
    * Constructs an empty <tt>LinkedHashMap</tt> instance with the
    * specified initial capacity, load factor and ordering mode.
    *
    * @param  initialCapacity the initial capacity
    * @param  loadFactor      the load factor
    * @param  accessOrder     the ordering mode - <tt>true</tt> for
    *         access-order, <tt>false</tt> for insertion-order
    * @throws IllegalArgumentException if the initial capacity is negative
    *         or the load factor is nonpositive
    */
   public LinkedHashMap(int initialCapacity,
                        float loadFactor,
                        boolean accessOrder) {
   
       super(initialCapacity, loadFactor);
       this.accessOrder = accessOrder;
   }

   //方法为protected ,摆明了是想被继承、重写
   protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
   
       return false;
   }

使用accessOrder来标识是使用访问顺序,还是插入顺序。默认为插入顺序。当accessOrder为访问顺序、容量固定时,即为LRU
举例如下:


class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V> {
   
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1882839504956564761L;
	
	private int capacity;
	
	public LRULinkedHashMap(int capacity) {
   
		super</
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java实现LRU缓存淘汰算法的方法与Python类似,也可以使用哈希表和双向链表来实现。下面是一个Java实现LRU缓存淘汰算法的代码示例: ```java class LRUCache { private Map<Integer, Node> map; private int capacity; private Node head; private Node tail; public LRUCache(int capacity) { this.capacity = capacity; map = new HashMap<>(); head = new Node(0, 0); tail = new Node(0, 0); head.next = tail; tail.prev = head; } public int get(int key) { if (map.containsKey(key)) { Node node = map.get(key); remove(node); add(node); return node.value; } else { return -1; } } public void put(int key, int value) { if (map.containsKey(key)) { Node node = map.get(key); node.value = value; remove(node); add(node); } else { if (map.size() == capacity) { Node node = tail.prev; remove(node); map.remove(node.key); } Node node = new Node(key, value); map.put(key, node); add(node); } } private void add(Node node) { Node next = head.next; head.next = node; node.prev = head; node.next = next; next.prev = node; } private void remove(Node node) { Node prev = node.prev; Node next = node.next; prev.next = next; next.prev = prev; } private class Node { int key; int value; Node prev; Node next; public Node(int key, int value) { this.key = key; this.value = value; } } } ``` 在这个实现中,我们同样使用了一个哈希表来查询节点是否存在以及快速删除节点,使用一个双向链表来维护缓存中节点的顺序。当有新的节点被访问时,我们将其移到链表头部,并且当缓存空间不足时,我们淘汰链表尾部的节点。同时,我们使用了一个Node内部类来封装节点的key和value,以及前驱和后继节点的指针。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值