最近看到好多人的面试题都是要求手写LRU,自己也想整理下这方面的知识点
页面置换算法:地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。
LRU算法:最近最少使用,简单来说就是将数据块中,每次使用过的数据放在数据块的最前端,然后将存在的时间最长的,也就是数据块的末端的数据剔除掉这就是LRU算法
有一种叫做有序字典的数据结构,综合了哈希表和链表,在 Python 中为 OrderedDict,在 Java 中为 LinkedHashMap。
from collections import OrderedDict
class LRUCache(OrderedDict):
def __init__(self, capacity: int):
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self:
return -1
self.move_to_end(key)
return self[key]
def put(self, key: int, value: int) -> None:
if key in self:
self.move_to_end(key)
self[key] = value
if len(self) > self.capacity:
self.popitem(last=False)
package com.example.write;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class LRU extends LinkedHashMap<String,String>{
private int capacity;
public LRU(int capacity){
super(capacity,0.75F,true);
this.capacity = capacity;
}
public String get(int key){
return super.getOrDefault(key,"-1");
}
public String put(String key, String value){
return super.put(key,value);
}
//判断是否删除最老数据的方法,默认是返回false
@Override
protected boolean removeEldestEntry(Map.Entry<String,String> entry){
return size() > capacity;
}
public static void main(String[] args) {
// Map<String, String> linkedHashMap = new LinkedHashMap<>(4, 0.75f, true);
// linkedHashMap.put("1","1");
// linkedHashMap.put("2","2");
// linkedHashMap.put("3","3");
// linkedHashMap.put("4","3");
// linkedHashMap.put("5","3");
// linkedHashMap.put("6","3");
// linkedHashMap.lruput("7","3");
//
// linkedHashMap.get("1");
// Iterator<Map.Entry<String,String>> iterator = linkedHashMap.entrySet().iterator();
// while (iterator.hasNext()){
//
// Map.Entry<String,String> entry = iterator.next();
// System.out.println("key="+ entry.getKey() + ",value=" + entry.getValue());
//
// }
LRU lru = new LRU(3);
lru.put("1","1");
lru.put("2","2");
lru.put("3","3");
lru.put("4","4");
lru.get("2");
Iterator<Map.Entry<String,String>> iterator = lru.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String,String> entry = iterator.next();
System.out.println("key="+ entry.getKey() + ",value=" + entry.getValue());
}
}
}
方法二 :哈希表 + 双向链表
package com.example.write;
import java.util.HashMap;
public class LRU2 {
class Node{
int key;
int val;
Node prev;
Node next;
public Node(int key,int value){
this.key = key;
this.val = value;
}
}
private HashMap<Integer,Node> res;
private Node head;
private int size;
private int capacity;
public LRU2(int capacity){
head = new Node(0,0);
head.next = null;
head.prev = null;
size = 0;
this.capacity = capacity;
res = new HashMap<>(capacity);
}
public int get(int key){
if(res.containsKey(key)){
Node tmp = res.get(key);
tmp.prev.next = tmp.next;
if(tmp.next != null){
tmp.next.prev = tmp.prev;
}
tmp.next = head.next;
tmp.prev = head;
if(head.next !=null){
head.next.prev = tmp;
}
head.next = tmp;
return res.get(key).val;
}
return -1;
}
public void put(int key,int value){
if(res.containsKey(key)){
Node tmp = head.next;
while(tmp != null){
if(tmp.key == key){
tmp.val = value;
tmp.prev.next = tmp.next;
if(tmp.next != null){
tmp.next.prev = tmp.prev;
}
tmp.next = head.next;
tmp.prev = head;
if(head.next != null){
head.next.prev = tmp;
}
head.next = tmp;
return;
}
tmp = tmp.next;
}
}else{
if(size == capacity){
Node tmp = head.next;
while(tmp.next !=null){
tmp = tmp.next;
}
res.remove(tmp.key);
tmp.prev.next = null;
tmp = null;
size--;
}
size++;
Node temp = new Node(key,value);
temp.next = head.next;
temp.prev = head;
if(head.next != null){
head.next.prev = temp;
}
head.next = temp;
res.put(key,temp);
}
}
}
双端链表 加 双端队列
public class Test {
class LRUnode{
String key;
String value;
LRUnode prey;
LRUnode next;
public LRUnode(String key,String value){
this.key =key;
this.value = value;
}
}
private HashMap<String,LRUnode> map ;
private int capacity;
private LRUnode head;
private LRUnode tail;
public Test(int capacity){
this.capacity = capacity;
map = new HashMap<>();
head = null;
tail = null;
}
public String get(String key){
LRUnode node = map.get(key);
remove(node,false);
setHead(node);
return node.value;
}
public void set(String key,String value){
LRUnode tmpnode = null;
if(map.containsKey(key)){
tmpnode = map.get(key);
tmpnode.value = value;
remove(tmpnode,false);
}else{
if(map.size() == capacity){
remove(tail,true);
}
tmpnode = new LRUnode(key,value);
map.put(key,tmpnode);
}
setHead(tmpnode);
}
private void setHead(LRUnode node){
if(head != null){
node.next = head;
head.prey = node;
}
head = node;
if(tail == null){
tail = node;
}
}
//flag 是要不要删除map里的key
private void remove(LRUnode node,Boolean flag){
if(node.prey != null){
node.prey.next = node.next;
}else{
head = node.next;
}
if(node.next != null){
node.next.prey = node.prey;
}else{
tail = node.prey;
}
node.next = null;
node.prey = null;
if(flag){
map.remove(node.key);
}
}
}