基於哈希鏈表的方式實現的LRU算法,通過Hash表存儲加快數據的訪問效率
節點類
package demo.LRU2;
/**
* @author koala
* @ClassName Node
* @date 2019/9/17 09:24
* @Description
* @Version V1.0
*/
public class Node {
String key;
Object value;
/**
* 上一個節點
*/
Node preNode;
/**
* 下一個節點
*/
Node nextNode;
/**
* 構造方法
* @param key
* @param value
*/
Node(String key,Object value){
this.key = key;
this.value = value;
this.preNode = null;
this.nextNode = null;
}
@Override
public String toString() {
return super.toString();
}
}
雙向鏈表類
這裏的雙向鏈表只存儲頭部節點和尾部節點;
package demo.LRU2;
/**
* @author koala
* @ClassName DoublyLinkedList
* @date 2019/9/17 10:09
* @Description 雙向鏈表
* @Version V1.0
*/
public class DoublyLinkedList {
public Node head;
public Node tail;
DoublyLinkedList(){
this.head = null;
this.tail = null;
}
/**
* 移動到頭部節點去
* @param node
*/
public void moveToHead(Node node){
if(node == null || node == head){
return ;
}
// 如果當前節點是尾節點;
if(tail == node){
// 把當前節點添加到頭部去
addToHead(node);
// 移除尾部的節點
removeTail();
}else{
// 當前節點前後節點交換
Node curNextNode = node.nextNode;
curNextNode.preNode = node.preNode;
Node curPreNode = node.preNode;
curPreNode.nextNode = curNextNode;
// 節點交換
head.preNode = node;
node.nextNode = head;
node.preNode = null;
head = head.preNode;
}
}
/**
* 刪除尾部節點
*/
public Node removeTail(){
if(tail == null){
return null;
}
/**
* 獲取當前尾部節點;
*/
Node n = tail;
if(head == tail){
head = null;
tail = null;
}else{
// 當前尾部節點的上一個節點就爲新的尾節點
tail = n.preNode;
// 尾節點的下一個節點置空
tail.nextNode = null;
}
//
return n;
}
/**
*
* @param node
*/
public void addToHead(Node node){
if(node == null){
return ;
}
/**
* 如果沒有上一級節點,證明是第一個節點,那假定前一個和後一個節點都是當前節點
*/
if(head == null){
head = node;
tail = node;
}else{
// 把當前節點放到鏈表最前面
node.nextNode = head;
head.preNode = node;
// 重新指定頭部節點
head = node;
}
}
@Override
public String toString() {
return super.toString();
}
}
緩存類
package demo.LRU2;
import java.util.HashMap;
import java.util.Map;
/**
* @author koala
* @ClassName Cache
* @date 2019/9/17 09:23
* @Description
* 最近最少使用算法 。 最近最少使用的元素,在接下來一段時間內,被訪問的概率也很低。
* * 即最近被使用的元素,在接下來一段時間內,被訪問概率較高。
* * <p>
* * 用鏈表的結構:
* * 鏈表頭部表示最後實現的數據,越靠近最後表示沒有使用的數據;
* * <p>
* 插入一個元素,如果沒有達到閾值,就放到最前面;如果超過最大的閾值,移除鏈表尾部的數據;
* *
* * 訪問一個元素,如果存在,則將該元素放到最前面;如果不存在;則返回空
* * <p>
*
* * 爲提高效率,採用hash表存儲數據
* @Version V1.0
*/
public class Cache {
private HashMap<String, Node> map;
/**
* 雙向鏈接實現LRU順序
*/
private DoublyLinkedList list;
/**
* 當前節點的大小
*/
private int size = 0;
/**
* 最大容量
*/
private int capacity = 10;
/**
* 初始化、並且賦值最大的容量
* @param capacity
*/
Cache(int capacity){
this.list = new DoublyLinkedList();
this.map = new HashMap<>();
this.capacity = capacity;
}
Cache(){
this.list = new DoublyLinkedList();
this.map = new HashMap<>();
}
/**
* 插入一個數據
* @param key
*/
public void put(String key,Object value){
if(!map.containsKey(key)){
Node n = new Node(key,value);
map.put(key,n);
list.addToHead(n);
// 如果超過最大的容量、移除最後一個數據
if(map.size() > capacity){
Node node = list.removeTail();
map.remove(node.key);
}
}else{
// 如果存在,就覆蓋value的值
Node node = map.get(key);
node.value = value;
list.moveToHead(node);
}
}
/**
* 根據鍵獲取值
* @param key
* @return
*/
public Object get(String key){
if(map.containsKey(key)){
Node node = map.get(key);
list.moveToHead(node);
return node.value;
}else{
return null;
}
}
public DoublyLinkedList getAllList(){
return list;
}
public Map getAllDataMap(){
return this.map;
}
}
測試類
package demo.LRU2;
/**
* @author koala
* @ClassName test
* @date 2019/9/17 10:55
* @Description
* @Version V1.0
*/
public class test {
public static void main(String[] args) {
Cache cache = new Cache(5);
cache.put("1","hello1");
cache.put("2","hello2");
cache.put("3","hello3");
cache.put("4","hello4");
cache.put("5","hello5");
cache.put("6","hello6");
cache.get("3");
for (Object map:cache.getAllDataMap().entrySet()) {
System.out.println(map.toString());
}
DoublyLinkedList doublyLinkedList = cache.getAllList();
System.out.println(doublyLinkedList.head.preNode);
System.out.println(doublyLinkedList.tail);
System.out.println("頭部節點, key:"+doublyLinkedList.head.key+";" +
"頭部節點上級節點:"+doublyLinkedList.head.preNode+"" +
"頭部節點下級節點:"+doublyLinkedList.head.nextNode.key);
System.out.println("尾部節點, key:"+doublyLinkedList.tail.key+";" +
"尾部節點上級節點:"+doublyLinkedList.tail.preNode.key+"" +
"尾部節點下級節點:"+doublyLinkedList.tail.nextNode);
}
}