概述
LRU(Least Recently Used)最近最少使用策略就像它的名字一样,是根据数据的历史访问记录来进行淘汰数据的,其思想是“如果数据最近被访问过,那么将来被访问的几率也更高;长期不被使用的数据在将来用到的几率也不大;当数据所占内存达到一定的阈值时,将移除最近最少被使用的数据”
步骤
- 如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。
- 如果此数据没有在缓存链表中,又可以分为两种情况:
如果此时缓存未满,则将此结点直接插入到链表的头部;
如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。
LRU缓存需要维护一个跟时间顺序关联的数据结构
使用LinkedHashMap
public class LRUCache{int capacity;Map<Integer, Integer> map;public LRUCache(int capacity) {this.capacity = capacity;map = new LinkedHashMap<>();}public int get(int key) {if (!map.containsKey(key)) {return -1;}//先删除旧的位置,再放入新位置Integer value = map.remove(key);map.put(key, value);return value;}public void put(int key, int value) {if (map.containsKey(key)) {map.remove(key);map.put(key, value);return;}map.put(key, value);//超出capacity,删除最久没用的,利用迭代器,删除第一个if (map.size() > capacity) {map.remove(map.entrySet().iterator().next().getKey());}}}
使用双链表+HashMap
public class LRUCache{//定义双向链表节点private class ListNode {int key;int val;ListNode pre;ListNode next;public ListNode(int key, int val) {this.key = key;this.val = val;pre = null;next = null;}}private int capacity;private Map<Integer, ListNode> map; //key->nodeprivate ListNode head; //dummy headprivate ListNode tail; //dummy tailpublic LRUCache(int capacity) {this.capacity = capacity;map = new HashMap<>();head = new ListNode(-1, -1);tail = new ListNode(-1, -1);head.next = tail;tail.pre = head;}public int get(int key) {if (!map.containsKey(key)) {return -1;}ListNode node = map.get(key);//先把这个节点删除,再接到尾部node.pre.next = node.next;node.next.pre = node.pre;moveToTail(node);return node.val;}public void put(int key, int value) {//直接调用这边的get方法,如果存在,它会在get内部被移动到尾巴,不用再移动一遍,直接修改值即可if (get(key) != -1) {map.get(key).val = value;return;}//不存在,new一个出来,如果超出容量,把头去掉ListNode node = new ListNode(key, value);map.put(key, node);moveToTail(node);if (map.size() > capacity) {map.remove(head.next.key);head.next = head.next.next;head.next.pre = head;}}private void moveToTail(ListNode node) {node.pre = tail.pre;tail.pre = node;node.pre.next = node;node.next = tail;}}
使用单链表
public class LRUCache{private class ListNode {int key, val;ListNode next;public ListNode(int key, int val) {this.key = key;this.val = val;this.next = null;}}private int capacity;private Map<Integer, ListNode> map; //key-> node.preprivate ListNode head; //dummyprivate ListNode tail;public LRUCache(int capacity) {this.capacity = capacity;map = new HashMap<>();head = new ListNode(-1, -1);tail = head;}public int get(int key) {if (!map.containsKey(key)) {return -1;}//map中存放的是要找的节点的前驱ListNode pre = map.get(key);ListNode cur = pre.next;//把当前节点删掉并移到尾部if (cur != tail) {pre.next = cur.next;map.put(cur.next.key, pre); //更新它后面node的前驱map.put(cur.key, tail);moveToTail(cur);}return cur.val;}public void put(int key, int value) {if (get(key) != -1) {map.get(key).next.val = value;return;}//不存在就new一个ListNode node = new ListNode(key, value);map.put(key, tail); //当前node的pre是tailmoveToTail(node);if (map.size() > capacity) {map.remove(head.next.key);map.put(head.next.next.key, head);head.next = head.next.next;}}private void moveToTail(ListNode node) {node.next = null;tail.next = node;tail = tail.next;}}
package maintype Node struct {key,val intnext,prev *Node}type LRUCache struct {cap int // 缓存容量cache map[int]*Node//判断数据是否存在head *Node //头指针tail *Node // 尾指针}func NewLRUCache(capacity int)*LRUCache{l :=&LRUCache{cap: capacity,cache: make(map[int]*Node),head: &Node{},tail: &Node{},}l.head.next = l.taill.tail.prev = l.headreturn l}// 双链表在头部插入数据func (l *LRUCache)insertHead(node *Node){tmp := l.head.nextl.head.next = nodenode.next = tmptmp.prev = nodenode.prev = l.head}// 双链表删除数据func (l *LRUCache)remove(node *Node){n := node.next// 获取后节点p := node.prev // 获取前节点p.next = nn.prev = pnode.next = nilnode.prev = nil}func(l *LRUCache)Get(key int)int{if n,ok:=l.cache[key];ok{l.remove(n)l.insertHead(n)return n.val}return -1}func(l *LRUCache)Put(key int,value int){if n,ok:=l.cache[key];ok{n.val =valuel.remove(n)l.insertHead(n)}else {if len(l.cache)==l.cap {//需要判断当前容器是否已经满了deleteNode := l.tail.prevdelete(l.cache,deleteNode.key)l.remove(deleteNode)}n :=&Node{key: key,val: value,}l.insertHead(n)l.cache[key]= n}}func main() {}
