1. 程式人生 > >LRU (最近最少使用) 快取機制:時間複雜度O(1)

LRU (最近最少使用) 快取機制:時間複雜度O(1)

/**
  * Double Linked List
  * 用了一個特別的雙向的ListNode,有了head和tail,這樣就大大加快了速度。     
* 主要加快的就是那個‘更新排位’的過程,找到item hashmap O(1), 做減法換位也都是O(1)
* Overall O(1)

*##### 巧妙點
* 1. head和tail特別巧妙:除掉頭和尾,和加上頭和尾,就都特別快。    
* 2. 用雙向的pointer: pre和next, 當需要除掉任何一個node的時候,只要知道要除掉哪一個,     
* 直接把node.pre和node.next耐心連起來就好了,node就自然而然的斷開不要了。     
* 一旦知道怎麼解決了,就不是很特別,並不是難寫的演算法:    
* moveToHead()    
* insertHead()    
* remove() 
**/
public class LRUCache {
    class DoubleLinkedListNode {
        int key, val;
        DoubleLinkedListNode next,prev;
        public DoubleLinkedListNode(int key, int val){
            this.key = key;
            this.val = val;
            next = null;
            prev = null;
        }
    }
    public int capacity;
    public HashMap<Integer, DoubleLinkedListNode> map;
    public DoubleLinkedListNode head, tail;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>();
        this.head = new DoubleLinkedListNode(-1, -1);
        this.tail = new DoubleLinkedListNode(-1, -1);
        head.next = tail;
        head.prev = tail;
        tail.next = head;
        tail.prev = head;
    }
    
    public int get(int key) {
        if(!map.containsKey(key)) {
            return -1;
        }
        DoubleLinkedListNode node = map.get(key);
        moveToHead(node);
        return node.val;
    }
    
    public void put(int key, int value) {
        if (map.containsKey(key)) {
            map.get(key).val = value;
            moveToHead(map.get(key));
        } else {
            DoubleLinkedListNode node = new DoubleLinkedListNode(key, value);
            if (map.size() >= this.capacity) {
                DoubleLinkedListNode rm = tail.prev;
                remove(rm);
                map.remove(rm.key);
            }
            insertHead(node);
            map.put(key, node);
        }
    }

    public void moveToHead(DoubleLinkedListNode node) {
        remove(node);
        insertHead(node);
    }
    
    //Helper functions
    /*
        Put node to front, where the latest item is at.
     */
    public void insertHead(DoubleLinkedListNode node) {
        DoubleLinkedListNode next = head.next;
        head.next = node;
        node.prev = head;
        node.next = next;
        next.prev = node;
    }

    /*
        Find front and end, link them.
     */
    public void remove(DoubleLinkedListNode node) {
        DoubleLinkedListNode front = node.prev;
        DoubleLinkedListNode end = node.next;
        front.next = end;
        end.prev = front;
    }  
}