LRUアルゴリズムを手書き
3368 ワード
LRU(Least Recently Used)アルゴリズムの概要
最近最も長い間使用されていないポリシーでは、最も長い間使用されていないデータ、つまり前回アクセスされた時間が現在最も長いデータを優先的に淘汰します.このアルゴリズムは、メモリ(キャッシュ)のデータがホットスポットデータであることを保証し、キャッシュヒット率を保証します.
アルゴリズム実装
思想:LRUのアルゴリズム思想によると、双方向チェーンテーブルをキャッシュとして私たちのデータを格納することができ、あるデータにアクセスするたびに、このノードを元の位置から削除し、チェーンテーブルのヘッダに挿入することができ、チェーンテーブルの末尾に最近最も長く使用されていないノードが格納されていることを保証することができる.ノード数がキャッシュ容量を超えると、末尾のノードが削除されます.質問:これでは、チェーンテーブル内のノードが秩序正しく遍歴できることを知っているため、時間の複雑さが高くなります.このように時間の複雑さはO(n)であり,これは受け入れられないので,例えばHashMapを用いてすべてのノードを格納する方法を考えることができる.これにより,検索時にはO(1)時間だけでターゲットノードを得ることができる.また、双方向チェーンテーブルを使用しているので、ターゲットノードを簡単に削除し、左右を接続することができます.
コード:
テストクラス:
実装:
最近最も長い間使用されていないポリシーでは、最も長い間使用されていないデータ、つまり前回アクセスされた時間が現在最も長いデータを優先的に淘汰します.このアルゴリズムは、メモリ(キャッシュ)のデータがホットスポットデータであることを保証し、キャッシュヒット率を保証します.
アルゴリズム実装
思想:LRUのアルゴリズム思想によると、双方向チェーンテーブルをキャッシュとして私たちのデータを格納することができ、あるデータにアクセスするたびに、このノードを元の位置から削除し、チェーンテーブルのヘッダに挿入することができ、チェーンテーブルの末尾に最近最も長く使用されていないノードが格納されていることを保証することができる.ノード数がキャッシュ容量を超えると、末尾のノードが削除されます.質問:これでは、チェーンテーブル内のノードが秩序正しく遍歴できることを知っているため、時間の複雑さが高くなります.このように時間の複雑さはO(n)であり,これは受け入れられないので,例えばHashMapを用いてすべてのノードを格納する方法を考えることができる.これにより,検索時にはO(1)時間だけでターゲットノードを得ることができる.また、双方向チェーンテーブルを使用しているので、ターゲットノードを簡単に削除し、左右を接続することができます.
コード:
テストクラス:
public class LRUTest {
public static void main(String[] args) {
LUR lur = new LUR<>(4);
for (int i =0;i<10;i++){
lur.put(i,i);
}
}
}
実装:
import java.util.HashMap;
import java.util.Iterator;
public class LUR implements Iterable {
private Node head;
private Node tail;
private HashMap map;
private int maxSize;
private class Node {
Node pre;
Node next;
K k;
V v;
public Node(K k, V v) {
this.k = k;
this.v = v;
}
}
public LUR(int maxSize) {
this.maxSize = maxSize;
this.map = new HashMap<>(maxSize * 4 / 3);
head = new Node(null, null);
tail = new Node(null, null);
head.next = tail;
tail.pre = head;
}
public V get(K key) {
if (!map.containsKey(key)) {
return null;
}
Node node = map.get(key);
unlink(node);
appendHead(node);
System.out.println(" :" + node.k);
return node.v;
}
public void put(K key, V value) {
if (map.containsKey(key)) {
Node node = map.get(key);
unlink(node);
}
Node node = new Node(key, value);
map.put(key, node);
appendHead(node);
System.out.println(" :" + node.k);
if (map.size() > maxSize) {
Node toRemove = removeTail();
System.out.println(" :" + toRemove.k);
map.remove(toRemove.k);
}
}
private Node removeTail() {
Node node = tail.pre;
Node pre = node.pre;
tail.pre = pre;
pre.next = tail;
node.next = null;
node.pre = null;
return node;
}
private void appendHead(Node node) {
Node next = head.next;
node.next = next;
next.pre = node;
node.pre = head;
head.next = node;
}
private void unlink(Node node) {
Node pre = node.pre;
Node next = node.next;
pre.next = next;
next.pre = pre;
node.pre = null;
node.next = null;
}
@Override
public Iterator iterator() {
return new Iterator() {
private Node curr = head.next;
@Override
public boolean hasNext() {
return curr != tail;
}
@Override
public K next() {
Node node = curr;
curr = curr.next; // 。
return node.k;
}
};
}
}