LRU缓存机制

题目描述

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?

样例

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

题解

  • LRU是OS中页面置换算法的一种,称为最近最久未使用算法。缺页时,计算内存中每个逻辑页面的上一次访问时间,移除上一次使用到当前时间最长的页面,即选择最长时间没有被访问的页面进行置换。
  • 在这道题中,我们利用哈希表和双端链表处理,哈希表存储每次添加的元素,并且将新操作的元素链接到双端链表的尾部。
  • 在双端链表中,头结点表示优先级最低,尾结点表示优先级最高。
  • 每次添加元素先判断map中是否存在,若存在则用新值覆盖旧值,并将链表中对应的节点移至尾部(即提升优先级);若不存在则将元素put到map中,并添加至链表尾部,然后判断是否超出容量,若超出则移除链表头部元素(即优先级最低的元素),并将该元素从map中移除。
import java.util.HashMap;
class Node{
	public int key;
	public int val;
	public Node pre;
	public Node next;
	public Node(int key,int val) {
		this.val=val;
		this.key=key;
	}
}
class NodeDoubleLinkedList{
	private Node head;
	private Node tail;
	public NodeDoubleLinkedList() {
		this.head=null;
		this.tail=null;
	}
	public void addNode(Node newNode) {
		if(newNode==null)
			return;
		if(this.head==null) {
			this.head=newNode;
			this.tail=newNode;
		}else {
			this.tail.next=newNode;
			newNode.pre=this.tail;
			this.tail=newNode;
		}
	}
	public void moveNodeToTail(Node node) {
		if(this.tail==node)
			return;
		if(this.head==node) {
			this.head=node.next;
			this.head.pre=null;
		}else {
			node.pre.next=node.next;
			node.next.pre=node.pre;
		}
		node.pre=this.tail;
		node.next=null;
		this.tail.next=node;
		this.tail=node;
	}
	public Node removeHead() {
		if(this.head==null)
			return null;
		Node res=this.head;
		if(this.head==this.tail) {
			this.head=null;
			this.tail=null;
		}else {
			this.head=res.next;
			res.next=null;
			this.head.pre=null;
		}
		return res;
	}
}
public class LRUCache {
	private int capacity;
	private HashMap<Integer,Node> nodeMap;
	private NodeDoubleLinkedList list;
	public LRUCache(int capacity) {
        if(capacity<1)
        	throw new RuntimeException("error");
        this.nodeMap=new HashMap<>();
        this.list=new NodeDoubleLinkedList();
        this.capacity=capacity;
    }
    
    public int get(int key) {
        if(nodeMap.containsKey(key)) {
        	Node res=nodeMap.get(key);
        	this.list.moveNodeToTail(res);
        	return res.val;
        }
        return -1;
    }
    public void put(int key, int value) {
    	if(nodeMap.containsKey(key)) {
    		Node res=nodeMap.get(key);
    		res.val=value;
    		list.moveNodeToTail(res);
    	}else {
    		Node newNode=new Node(key,value);
    		nodeMap.put(key, newNode);
    		list.addNode(newNode);
    		if(this.nodeMap.size()==capacity+1) {
    			this.removeMostUnused();
    		}
    	}
    }
	private void removeMostUnused() {
		Node res=list.removeHead();
		nodeMap.remove(res.key);
	}
	public static void main(String[] args) {
		LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
		cache.put(1, 1);
		cache.put(2, 2);
		System.out.println(cache.get(1));      // 返回  1
		cache.put(3, 3);    // 该操作会使得2移除
		System.out.println(cache.get(2));     // 返回 -1 (未找到)
		cache.put(4, 4);    // 该操作会使得1移除
		cache.get(1);       // 返回 -1 (未找到)
		cache.get(3);       // 返回  3
		cache.get(4);       // 返回  4
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值