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
这里采用双向链表和HashMap的结构,HashMap中存储的是key和Node,Node中存储的是key和value。HashMap能保证查找的时间复杂度是O(1),双向链表保证的是增删的时间复杂度是O(1)
1 class LRUCache { 2 3 public int capacity; 4 public Map<Integer, Node> map; 5 public Node head;//设一个虚拟的头结点 6 public Node tail;//设一个虚拟的尾结点 7 public int size;//链表长度 8 9 public LRUCache(int capacity) { 10 this.capacity = capacity; 11 this.map = new HashMap<>(); 12 head = new Node(0, 0); 13 tail = new Node(0, 0); 14 15 head.pre = null; 16 head.next = tail; 17 tail.pre = head; 18 tail.next = null; 19 } 20 21 public void removeNode(Node node){ 22 node.pre.next = node.next; 23 node.next.pre = node.pre; 24 } 25 26 public void addToHead(Node node){ 27 node.next = head.next; 28 node.next.pre = node; 29 node.pre = head; 30 head.next = node; 31 } 32 33 public int get(int key) { 34 int value = -1; 35 if(map.get(key) != null){ 36 value = map.get(key).value; 37 removeNode(map.get(key)); 38 addToHead(map.get(key)); 39 } 40 return value; 41 } 42 43 public void put(int key, int value) { 44 if(map.get(key) != null){ 45 removeNode(map.get(key)); 46 map.remove(key); 47 size--; 48 } 49 Node node = new Node(key, value); 50 map.put(key, node); 51 if(size < capacity){ 52 addToHead(node); 53 size++; 54 }else{ 55 Node remove = tail.pre; 56 removeNode(remove); 57 map.remove(remove.key); 58 addToHead(node); 59 } 60 } 61 } 62 63 class Node{ 64 int key; 65 int value; 66 public Node(int key, int value) { 67 super(); 68 this.key = key; 69 this.value = value; 70 } 71 Node pre; 72 Node next; 73 }