运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
示例:
解
方法一:哈希表 + 双向链表
双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。
哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。
class LRUCache { private int capacity; private int size; private Map<Integer, DLinkedNode> cache = new HashMap(); private DLinkedNode head,tail; class DLinkedNode { int key; int value; DLinkedNode prev; DLinkedNode next; public DLinkedNode() {} public DLinkedNode(int _key, int _value) {key = _key; value = _value;} } public LRUCache(int capacity) { this.capacity = capacity; head = new DLinkedNode(); tail = new DLinkedNode(); head.next = tail; tail.prev = head; } public int get(int key) { DLinkedNode node = cache.get(key); if(node == null) { return -1; } else { moveToHead(node); return node.value; } } public void put(int key, int value) { DLinkedNode node = cache.get(key); if(node == null) { DLinkedNode newNode = new DLinkedNode(key, value); cache.put(key, newNode); addToHead(newNode); size++; if(size > capacity) { DLinkedNode tailNode = removeTail(); cache.remove(tailNode.key); size --; } } else { node.value = value; moveToHead(node); } } private void addToHead(DLinkedNode node) { DLinkedNode preSecondNode = head.next; head.next = node; node.prev = head; preSecondNode.prev = node; node.next = preSecondNode; } private void moveToHead(DLinkedNode node) { DLinkedNode appendPrevNode = node.prev; DLinkedNode appendNextNode = node.next; appendPrevNode.next = appendNextNode; appendNextNode.prev = appendPrevNode; DLinkedNode preSecondNode = head.next; head.next = node; node.prev = head; node.next = preSecondNode; preSecondNode.prev = node; } private DLinkedNode removeTail() { DLinkedNode tailNode = tail.prev; DLinkedNode pretailNode = tailNode.prev; tail.prev = pretailNode; pretailNode.next = tail; return tailNode; } }