java中的LRU缓存实现

时间:2020-02-23 14:36:03  来源:igfitidea点击:

在本教程中,我们将在Java中看到LRU缓存实现。

问题

在Java中设计最近使用最近使用的缓存实现。
它应该有以下属性。
bounded size:它应该有界大小来照顾记忆范围。
Fast access:在我们设计缓存时,我们应该能够更快地获取或者更新条目。
Evict least recently used entry:缓存应拒绝最近最近使用的条目如果达到容量。

解决方案

使用HashMap和双链接列表

我们需要做查询 O(1)然后,Hashmap是显而易见的选择,但我们也需要照顾最近的最近使用的条目。

如果我们已经知道节点,我们需要找到一个数据结构,该数据结构可以在O(1)时间内删除/添加。
我们可以为此目的使用双重链接列表,因为如果已经了解节点,它会在O(1)时间内提供删除/添加。

HashMap将获得操作 O(1) timeDoube linked list将删除/加入 O(1) time

这是Java中LRU缓存实现的简单程序。

package org.igi.theitroad;
 
import java.util.HashMap;
 
class Node{
	int key;
	int value;
	Node prev;
	Node next;
 
	public Node(int key, int value){
		this.key = key;
		this.value = value;
	}
}
public class LRUCache {
	int capacity;
	HashMap<Integer, Node> map = new HashMap<Integer, Node>();
	Node head=null;
	Node end=null;
 
	public LRUCache(int capacity) {
		this.capacity = capacity;
	}
 
	public int get(int key) {
		if(map.containsKey(key)){
			Node n = map.get(key);
			delete(n);
			setHead(n);
			return n.value;
		}
 
		return -1;
	}
 
	/*This method will delete node*/
	public void delete(Node node){
		if(node.prev!=null){
			node.prev.next = node.next;
		}else{
			head = node.next;
		}
 
		if(node.next!=null){
			node.next.prev = node.prev;
		}else{
			end = node.prev;
		}
 
	}
 
	/*This method will make passed node as head*/
	public void setHead(Node node){
		node.next = head;
		node.prev = null;
 
		if(head!=null)
			head.prev = node;
 
		head = node;
 
		if(end ==null)
			end = head;
	}
 
	public void set(int key, int value) {
		if(map.containsKey(key)){
			//update the old value
			Node old = map.get(key);
			old.value = value;
			delete(old);
			setHead(old);
		}else{
			Node newNode = new Node(key, value);
			if(map.size()>=capacity){
				
				map.remove(end.key);
				//remove last node
				delete(end);
				setHead(newNode);
 
			}else{
				setHead(newNode);
			}    
 
			map.put(key, newNode);
		}
	}	
	
	public static void main(String[] args) throws java.lang.Exception {
		LRUCache lrucache = new LRUCache(4);
		lrucache.set(1, 100);
		lrucache.set(10, 99);
		lrucache.set(15, 98);
		lrucache.set(10, 97);
		lrucache.set(12, 96);
		lrucache.set(18, 95);
		lrucache.set(1, 94);
 
		System.out.println(lrucache.get(1));
		System.out.println(lrucache.get(10));
		System.out.println(lrucache.get(15));
 
	}
}

运行上面的程序时,我们将得到以下输出:

94
97
-1

正如我们所看到的,在过去的4个条目中,我们没有 15作为关键。
这是我们获得的原因 -1为了它。

使用linkedhashmap.

我们可以使用LinkedHashMap创建LRU缓存。

LinkedHashMap有一个构造函数,我们可以其中指定访问顺序。

如果你通过了 accessOrder作为真,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;
    }

我们还将覆盖命名的方法 removeEldestEntry()它会返回 true以防万一 size()大于 capacity

让我们创建一个名为的程序 LRUCache

package org.igi.theitroad;
import java.util.LinkedHashMap; 
import java.util.Map; 
  
class LRUCache { 
    private LinkedHashMap<Integer, Integer> cacheMap; 
    public LRUCache(int capacity) 
    { 
        cacheMap = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) { 
            protected boolean removeEldestEntry(Map.Entry eldest) 
            { 
                return size() > capacity; 
            } 
        }; 
    } 
  
    //This method works in O(1) 
    public int get(int key) 
    { 
        return cacheMap.getOrDefault(key, -1); 
    } 
  
    //This method works in O(1) 
    public void set(int key, int value) 
    { 
        cacheMap.put(key, value); 
    } 
} 
  
public class LRUUsingLinkedHashMapMain { 
  
    public static void main(String[] args) 
    { 
    	LRUCache lrucache = new LRUCache(4);
		lrucache.set(1, 100);
		lrucache.set(10, 99);
		lrucache.set(15, 98);
		lrucache.set(10, 97);
		lrucache.set(12, 96);
		lrucache.set(18, 95);
		lrucache.set(1, 94);
 
		System.out.println(lrucache.get(1));
		System.out.println(lrucache.get(10));
		System.out.println(lrucache.get(15));
  
    } 
}

如您所见,在最后4个条目中,我们没有键“ 15”。 这就是我们为此得到-1的原因。