LRU
双向链表+哈希表
class Node {
String key;
int value;
Node pre;
Node next;
public Node(String key, int value) {
this.key = key;
this.value = value;
}
}
class biLinkedList{
Node head;
Node tail;
public biLinkedList() {
this.head = null;
this.tail = null;
}
public void addNode(Node newNode) {
if (newNode == null) {
return;
}
if (this.head == null) {
this.head = newNode;
}else {
this.tail.next = newNode;
newNode.pre = this.tail;
newNode.next = null;
}
this.tail = newNode;
}
public void moveToTail(Node node) {
if (this.tail == node) {
return;
}
if (node == this.head) {
this.head = node.next;
this.head.pre = null;
}else {
node.pre.next = node.next;
node.next.pre = node.pre;
}
this.tail.next = node;
node.pre = this.tail;
node.next = null;
this.tail = node;
}
public Node removeHead() {
if (this.head == null) {
return null;
}
Node res = this.head;
if (this.head == this.tail) {
this.head = null;
this.tail = null;
}else {
this.head = res.next;
this.head.pre = null;
res.next = null;
}
return res;
}
}
public class LRU {
biLinkedList nodeList;
HashMap<String, Node> keyNodeMap;
int capacity;
public LRU(int capacity) {
if (capacity < 1) {
throw new RuntimeException("capacity too small");
}
this.capacity = capacity;
keyNodeMap = new HashMap<>();
nodeList = new biLinkedList();
}
public int get(String key) {
if (keyNodeMap.containsKey(key)) {
Node res = keyNodeMap.get(key);
this.nodeList.moveToTail(res);
return res.value;
}
return -999;
}
public void set(String key, int value) {
if (keyNodeMap.containsKey(key)) {
Node res = keyNodeMap.get(key);
res.value = value;
nodeList.moveToTail(res);
}else {
Node newNode = new Node(key, value);
keyNodeMap.put(key, newNode);
nodeList.addNode(newNode);
if (capacity + 1 == keyNodeMap.size()) {
removeMostUnusedCache();
}
}
}
public void removeMostUnusedCache() {
Node removeNode = nodeList.removeHead();
keyNodeMap.remove(removeNode.key);
}
public static void main(String[] args) {
LRU test = new LRU(3);
test.set("A", 1);
test.set("B", 2);
test.set("C", 3);
System.out.println(test.get("B"));
System.out.println(test.get("A"));
test.set("D", 4);
System.out.println(test.get("D"));
System.out.println(test.get("C"));
}
}
结果:
2
1
4
-999
LFU
package lfu;
import java.util.HashMap;
public class LFU {
public static class Node{
int key;
int value;
int times;
Node up;
Node down;
public Node(int key, int value, int times) {
this.key = key;
this.value = value;
this.times = times;
}
}
public static class LFUCache{
public static class NodeList{
Node head;
Node tail;
NodeList pre;
NodeList next;
public NodeList(Node node) {
this.head = node;
this.tail = node;
}
public void addNodeToHead(Node newNode){ // 新来的节点从头部添加,因而尾部是最早添加
newNode.down = head;
head.up = newNode;
head = newNode;
}
public boolean isEmpty() {
return head == null;
}
public void deleteNode(Node node) {
if (head == tail) {
head = null;
tail = null;
}else {
if (node == head) {
head = head.down;
head.up = null;
}else if (node == tail) {
tail = tail.up;
tail.down = null;
}else {
node.down.up = node.up;
node.up.down = node.down;
}
}
node.up = null;
node.down = null;
}
}
int capacity;
int size;
NodeList headList;
HashMap<Integer, Node> records; // key对应的Node
HashMap<Node, NodeList> heads; // Node 在哪个NodeList中
public LFUCache(int capacity, NodeList headList, HashMap<Integer, Node> records, HashMap<Node, NodeList> heads) {
this.capacity = capacity;
this.size = 0;
this.headList = null;
this.records = new HashMap<>();
this.heads = new HashMap<>();
}
// 添加或修改
public void set(int key, int value) {
if (records.containsKey(key)) { // 若key已经存在
Node node = records.get(key); // 得到其node
node.times++; // 频数+1
node.value = value; // 更新值
NodeList curNodeList = heads.get(node); // 得到其所在LinkList
move(node, curNodeList); // 将node从所在LinkList中删除并将频数更新后的node插入到合适的LinkList中
}else { // key不存在
if (size == capacity) { // 容量满了,说明要移除一个最久没使用的,那么headList指向的那串链表的tail即为待删除节点
Node tail = headList.tail;
headList.deleteNode(tail);
modifieyHeadList(headList); // 如果删除节点后这个链表为空了,那么就把整串链表删掉
records.remove(tail.key);
heads.remove(tail);
size--;
}
Node newNode = new Node(key, value, 1);
if (headList == null) { // 若headList一个都没有则创建一个
headList = new NodeList(newNode);
}else {
if (headList.head.times == 1) { // 如果第一条链的频数是1,直接添加即可
headList.addNodeToHead(newNode);
}else { // 说明头链频数不是1,那么就新建一个
NodeList newList = new NodeList(newNode);
newList.next = headList;
headList.pre = newList;
headList = newList;
}
}
records.put(key, newNode);
heads.put(newNode, headList);
size++;
}
}
public boolean modifieyHeadList(NodeList nodeList) {
if (nodeList.isEmpty()) {
if (nodeList == headList) { // 如果待删除那条链就是头链
headList = nodeList.next;
nodeList.next = null;
if (headList != null) {
headList.pre = null;
}
}else { // 待删除那条链不是头链
nodeList.pre.next = nodeList.next;
if (nodeList.next != null) {
nodeList.next.pre = nodeList.pre;
}
}
return true;
}
return false;
}
public void move(Node node, NodeList oldNodeList) {
oldNodeList.deleteNode(node);
NodeList preList = modifieyHeadList(oldNodeList) ? oldNodeList.pre: oldNodeList;
NodeList nextList = oldNodeList.next;
if (nextList == null) { // 如果插入位置为空
NodeList newList = new NodeList(node);
if (preList != null) {
preList.next = newList;
}
newList.pre = preList;
if (headList == null) {
headList = newList;
}
heads.put(node, newList);
}else {
if (nextList.head.times == node.times) { // 如果更新后的词频在nextList这条链中,直接添加
nextList.addNodeToHead(node);
heads.put(node, nextList);
}else { // 新建一条链插在pre和next之间
NodeList newList = new NodeList(node);
if (preList != null) {
preList.next = newList;
}
newList.pre = preList;
newList.next = nextList;
nextList.pre = newList;
if (headList == nextList) {
headList = newList;
}
heads.put(node, newList);
}
}
}
public int get(int key) {
if (!records.containsKey(key)) {
return -999;
}
Node node = records.get(key);
node.times++;
NodeList curNodeList = heads.get(node);
move(node, curNodeList);
return node.value;
}
}
}