讀書筆記——漫畫算法(8) LRU緩存的實現

LRU,Least Recently Used,最近最少使用;一種資源管理算法

按照字面的意思,也可以理解爲緩存淘汰算法:最近最少訪問的資源,我們就從緩存中淘汰出去,以免長時間佔用內存且不經常訪問;

首先,我們定義基礎的數據結構:

public class LRUCache {

    // 自定義鏈表節點
	private static class Node {
        String key;
        String value;
        Node pre;
        Node next;

        Node(String key, String value) {
            this.key = key;
            this.value = value;
        }
    }
	
	// 用於高效訪問的HashMap
    private Map<String, Node> map = new HashMap<>();

    // 閾值,限制資源在內存中的數量
    private int limit;
    
    // ------------- 維護一個雙向鏈表
    // 鏈表頭節點
    private Node head;
    // 鏈表尾節點
    private Node tail;

    public LRUCache(int limit) {
        this.limit = limit;
    }
}

下面我們定義外界訪問的基礎方法:

// 對外調用的put函數,用來向緩存中存入數據(或者更新)
public void put(String key, String value);

// 外部調用函數,獲取以key爲鍵的值
public String get(String key);

// 外部調用的函數,用來移除給定的key節點
public void remove(String key);

下面是方法的實現:

/**
* 對外調用的put函數,用來向緩存中存入數據(或者更新)
* @param key
* @param value
*/
public void put(String key, String value) {
   Node node = map.get(key);
   if(node == null) {
       // 如果節點不存在
       node = new Node(key, value);
       if(map.size() >= limit) {
           // 如果size要超出容量限制了,先移除,再添加
           removeNode(head);
       }
   } else {
       // 如果節點存在,則更新
       node.value = value;
       removeNode(node);
   }
   addNode(node);
}

/**
* 外部調用函數,獲取以key爲鍵的值
* @param key
* @return
*/
public String get(String key) {
   Node node = map.get(key);
   if(node == null) {
       return null;
   }

   String value = node.value;
   removeNode(node);
   addNode(node);
   return value;
}

/**
* 外部調用的函數,用來移除給定的key節點
* @param key
*/
public void remove(String key) {
   Node node = map.get(key);
   removeNode(node);
}

其中涉及到幾個子方法:
removeNode(node); 從鏈表中刪除節點
addNode(node); 添加節點到鏈表尾部

private void removeNode(Node node) {
    if(head == null || tail == null) {
        throw new RuntimeException("Cache is empty...");
    }

    if(node == head) {
        // 如果是移除頭節點
        head = head.next;
        if(head != null) {
            head.pre.next = null;
            head.pre = null;
        }
    } else if(node == tail) {
        // 如果是移除尾節點
        tail = tail.pre;
        if(tail != null) {
            tail.next.pre = null;
            tail.next = null;
        }
    } else {
        Node tmp = head;
        while(tmp != null) {
            if(node == tmp) {
                Node pre = node.pre;
                Node next = node.next;
                node.pre = null;
                node.next = null;
                pre.next = next;
                next.pre = pre;
                break;
            }
            tmp = tmp.next;
        }
    }
    map.remove(node.key);
}

private void addNode(Node node) {
    if(head == null || tail == null) {
        head = tail = node;
    } else {
        node.pre = tail;
        tail.next = node;
        tail = node;
    }
    map.put(node.key, node);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章