第一次看到這個題目,我懵逼了,啥是LRU,因而乎我去百度了一下,大概的意思是這樣的,LRU是Least Recently Used的縮寫,即最近最少使用,選擇最近最久未使用的key予以淘汰。 大概瞭解後我想到(實際想了半天。。。而且還參考了網上的其餘人的一些思路)node
既然要頻繁的刪除和插入,那確定首選鏈表,大概思路分以下幾步: 1.須要一個雙向鏈表,頭節點和尾節點 2.HashMap存儲key, HashMap的Value爲雙向鏈表LRU的Node節點 3.put插入時判斷該key是否存在,若是不存在,再判斷是否空間滿了,滿了就刪除末尾節點(最少使用節點),而後把新插入元素放到頭節點,若是沒滿則插入到鏈表頭節點,若是已存在,則移動該節點到頭節點 4.get獲取節點時有則返回,而且把該節點移動到鏈表的頭節點bash
代碼實現以下:測試
/**
* 雙向鏈表
*/
class LinkNode {
/**
* 前節點
*/
LinkNode pre;
/**
* 後節點
*/
LinkNode next;
int key;
int val;
}
public class LRUCache {
private int capacity;
private LinkNode head;
private LinkNode tail;
private HashMap<Integer,LinkNode> cache;
public LRUCache(int capacity) {
this.capacity=capacity;
cache = new HashMap<>(capacity);
}
public int get(int key) {
LinkNode res = cache.get(key);
if(res == null){
return -1;
}
moveNodeToFirst(res);
return res.val;
}
public void put(int key, int value) {
LinkNode tempLinkNode = cache.get(key);
if(tempLinkNode == null){
if(cache.size() >= capacity){
removeLastNode();
}
tempLinkNode = new LinkNode();
tempLinkNode.key = key;
}
tempLinkNode.val = value;
moveNodeToFirst(tempLinkNode);
cache.put(key, tempLinkNode);
}
/**
* put或者get時移動該節點到鏈表的頭節點
* @param node
*/
private void moveNodeToFirst(LinkNode node) {
//空鏈表時放入第一個元素
if(head == null){
tail = head = node;
return;
}
//鏈表的頭部
if (head == node) {
return;
}
//鏈表的尾部
else if(tail == node){
//把他前面的節點變成尾節點(他要被移動到鏈表開頭了)
tail = tail.pre;
}
//在鏈表中間的節點
else if(node.next != null || node.pre != null){
//節點被移動到頭部後,相鄰節點的先後節點值變化
assert node.pre != null;
node.pre.next = node.next;
assert node.next != null;
node.next.pre = node.pre;
}
//原來的鏈表頭部,變成第二個
node.next = head;
//節點被移動到頭部後,相鄰節點的先後節點值變化
head.pre = node;
//放到頭部後他的前節點爲空
node.pre = null;
//放到鏈表頭部
head = node;
}
/**
* 超過hashMap容量時刪除最後一個元素,即最少使用元素
*/
private void removeLastNode() {
LinkNode tempLinkNode = tail;
//倒數第二個節點變成最後一個節點
tail = tail.pre;
if(tail != null){
tail.next = null;
}else{
head = null;
}
cache.remove(tempLinkNode.key);
}
}
複製代碼
測試ui
public static void main(String[] args) {
LRUCache cache = new LRUCache( 2 );
cache.put(1, 1);
cache.put(2, 2);
System.out.println("獲取1的值" + cache.get(1));
cache.put(3, 3);
System.out.println("key:3已插入, key:2,被刪除");
System.out.println("獲取2的值" + cache.get(2));
cache.put(4, 4);
System.out.println("key:4已插入, key:1,被刪除");
System.out.println("獲取1的值" + cache.get(1));
System.out.println("獲取3的值" + cache.get(3));
System.out.println("獲取4的值" + cache.get(4));
}
複製代碼
結果this
獲取1的值:1
key:3已插入, key:2,被刪除
獲取2的值:-1
key:4已插入, key:1,被刪除
獲取1的值-1
獲取3的值:3
獲取4的值:4
複製代碼
參考資料:cloud.tencent.com/developer/a… www.jianshu.com/p/34c03210c…spa