class LRUCache {
private HashMap<Integer,Node>map;
private DoubleList cache;
private int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
cache = new DoubleList();
}
public int get(int key) {
if(!map.containsKey(key)){
return -1;
}
makeRecently(key);
return map.get(key).val;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
// 删除旧的数据
deleteKey(key);
// 新插入的数据为最近使用的数据
addRecently(key, value);
return;
}
if (capacity == cache.size()) {
// 删除最久未使用的元素
removeLeastRecently();
}
// 添加为最近使用的元素
addRecently(key, value);
}
private void makeRecently(int key){
Node x = map.get(key);
System.out.println("recently:"+x.key);
cache.removeList(x);
cache.addList(x); //重新插回队尾
}
private void addRecently(int key,int val){
Node x = new Node(key,val);
cache.addList(x);
map.put(key,x);
}
/* 删除最久未使用的元素 */
private void removeLeastRecently() {
// 链表头部的第一个元素就是最久未使用的
Node deletedNode = cache.removeListFirst();
// 同时别忘了从 map 中删除它的 key
int deletedKey = deletedNode.key;
System.out.println(deletedKey);
map.remove(deletedKey);
}
private void deleteKey(int key){
Node x = map.get(key);
cache.removeList(x);
map.remove(key);
}
}
class Node{
public Node next;
public Node pre;
public int key;
public int val;
public Node(int key,int val){
this.key = key;
this.val = val;
}
}
class DoubleList{
private Node head;
private Node tail;
private int size;
public DoubleList(){
head = new Node(0,0);
tail = new Node(0,0);
head.next = tail;
tail.pre =head;
size = 0;
}
public void addList(Node x){
//从尾部插入
x.pre = tail.pre;
tail.pre.next=x;
x.next = tail;
tail.pre = x;
size++;
}
public void removeList(Node x){
x.pre.next = x.next;
x.next.pre = x.pre;
size--;
}
public Node removeListFirst(){
if(head.next==tail){
return null;
}
//head.next = head.next.next;
//head.next.next.pre=head; 要返回删除的这个节点
Node first = head.next;
removeList(first);
return first;
}
public int size(){
return size;
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
class LRUCache {
int cap;
LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
public LRUCache(int capacity) {
this.cap = capacity;
}
public int get(int key) {
if (!cache.containsKey(key)) {
return -1;
}
// 将 key 变为最近使用
makeRecently(key);
return cache.get(key);
}
public void put(int key, int val) {
if (cache.containsKey(key)) {
// 修改 key 的值
cache.put(key, val);
// 将 key 变为最近使用
makeRecently(key);
return;
}
if (cache.size() >= this.cap) {
// 链表头部就是最久未使用的 key
int oldestKey = cache.keySet().iterator().next();
cache.remove(oldestKey);
}
// 将新的 key 添加链表尾部
cache.put(key, val);
}
private void makeRecently(int key) {
int val = cache.get(key);
// 删除 key,重新插入到队尾
cache.remove(key);
cache.put(key, val);
}
}
虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。
关 注 点 | 结 论 |
---|---|
LinkedHashMap是否允许空 | Key和Value都允许空 |
LinkedHashMap是否允许重复数据 | Key重复会覆盖、Value允许重复 |
LinkedHashMap是否有序 | 有序 |
LinkedHashMap是否线程安全 | 非线程安全 |
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{
private transient Entry<K,V> header;
/**
* The iteration ordering method for this linked hash map: true
* for access-order, false for insertion-order.
* true表示最近最少使用次序,false表示插入顺序
*/
private final boolean accessOrder;
...
}
LinkedHashMap是HashMap的子类,自然LinkedHashMap也就继承了HashMap中所有非private的方法。
关于HashMap原理做了点笔记,也没有太理解,参考文章:
https://blog.csdn.net/qq_42194397/article/details/126059459?spm=1001.2014.3001.5501