LeetCode題解: LRU Cache 緩存設計

 

LeetCode題解: LRU Cache 緩存設計

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: https://blog.csdn.net/leread/article/details/41841965

設計並實現最近最久未使用(Least Recently Used)緩存。html

連接:https://oj.leetcode.com/problems/lru-cache/java

題目描述:node

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.mysql

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.面試

設計並實現最近最久未使用的緩存數據結構,支持 get 和 set 操做.算法

get()-若是 key 存在,返回對應的 value 值,不然返回 -1.sql

set()-插入 key 對應的 value 到緩存中,若是緩存已滿,將最近最久未使用的元素從緩存中移除。緩存

要實現這個設計,咱們先回顧一下大學課堂上的知識。
LRU,即最近最少使用,是操做系統內存管理的一種頁面置換算法,
常見的頁面置換算法,最佳置換算法(OPT,理想置換算法),先進先出置換算法(FIFO),
最近最久未使用算法(LRU),最少使用算法。數據結構


其中,最佳置換算法是一種理想狀況下的頁面置換算法,實際上不可能實現。該算法的基本思想是發生缺頁時,有些頁面在內存中,其中有一頁將很快被訪問(也包含緊接着的下一條指令的那頁),而其餘頁面則可能要到十、100或者1000條指令後纔會被訪問,每一個頁面均可以用在該頁面首次被訪問前所要執行的指令數進行標記。最佳頁面置換算法規定標記最大的頁應該被置換。但當缺頁發生時,操做系統沒法知道各個頁面下一次是在何時被訪問。這個算法沒法實現,但能夠用於對可實現算法的性能進行衡量。app

另外兩種主要算法,LFU算法-實現緩存,FIFO算法-實現緩存,能夠查看這裏

LRU的實現方法有不少,傳統的LRU實現方法:

1.計數器。最簡單的狀況是使每一個頁表項對應一個使用時間字段,並給CPU增長一個邏輯時鐘或計數器。每次存儲訪問,該時鐘都加1。每當訪問一個頁面時,時鐘寄存器的內容就被複制到相應頁表項的使用時間字段中。這樣咱們就能夠始終保留着每一個頁面最後訪問的「時間」。在置換頁面時,選擇該時間值最小的頁面。
2.棧。用一個棧保留頁號。每當訪問一個頁面時,就把它從棧中取出放在棧頂上。這樣一來,棧頂老是放有目前使用最多的頁,而棧底放着目前最少使用的頁。因爲要從棧的中間移走一項,因此要用具備頭尾指針的雙向鏈連起來。

Java語言能夠利用 LinkedHashMap, LinkedHashMap 是有序的哈希表,能夠保存記錄的插入順序,而且按使用順序排列。
重寫其中的removeEldestEntry(Map.Entry)方法,就能夠實現LRU算法。

我看了一下,在Mysql Jdbc Util和Apache的不少Jar包中,都是使用LinkedHashMap實現LRUCache。
下面的代碼來自mysql-connector-java-5.1.18-bin.jar。

複製代碼
package com.mysql.jdbc.util;

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache extends LinkedHashMap
{

    public LRUCache(int maxSize)
    {
        super(maxSize, 0.75F, true);
        maxElements = maxSize;
    }

    protected boolean removeEldestEntry(java.util.Map.Entry eldest)
    {
        return size() > maxElements;
    }

    private static final long serialVersionUID = 1L;
    protected int maxElements;
}
複製代碼

 不過LeetCode的OJ不支持這樣實現,將上面的代碼修改後提交,提示 Comoile Error .

JDK中,LinkedHashMap是經過繼承HashMap,維護一個雙鏈表實現,
當某個Cache位置被命中,經過調整鏈表的指向將該位置調整到頭位置,新加入的內容直接放在鏈表頭,在屢次進行Cache操做後,最近使用的Cache就會向鏈表頭部移動,鏈表尾部就是命中次數最少,最久未使用的Cache。空間充滿時,移除尾部的數據就能夠了。

題目有幾點須要注意,一個是Key不存在的狀況,一個是緩存設計要求Key惟一。

下面使用雙向鏈表(雙鏈表)實現LRU Cache,如下代碼提交AC。

複製代碼
import java.util.HashMap;
/**
 * Design and implement a data structure for Least Recently Used (LRU) cache. 
 * It should support the following operations: get and set.
 * get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
 * set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity,
 *  it should invalidate the least recently used item before inserting a new item.
 *  近期最少使用算法 設計緩存
 */
public class LRUCache {
    
    private int cacheSize;//緩存容量
    private int currentSize;//當前容量
    private HashMap<Object, CacheNode> nodes;//緩存容器
    private CacheNode head;//鏈表頭
    private CacheNode last;//鏈表尾

    class CacheNode{
        CacheNode prev;//前一節點
        CacheNode next;//後一節點
        int value;//值
        int key;//鍵
        CacheNode() {
        }
    }
    
    //初始化緩存
    public LRUCache(int capacity) {
        currentSize=0;
        cacheSize=capacity;
        nodes=new HashMap<Object, CacheNode>(capacity);    
    }
        
    public Integer get(int key) {
        CacheNode node = nodes.get(key);
        if (node != null) {
            move(node);
            return node.value;
        } else {
            return -1;//error code
        }
            
    }
        
    public void set(int key, int value) {
        CacheNode node = nodes.get(key);
        //重複Key
        if(node!=null){
            node.value=value;
            move(node);
            nodes.put(key, node);
        }else
           {//key未重複,正常流程
            node =new CacheNode();
            if(currentSize>=cacheSize){
                if (last != null){//緩存已滿,進行淘汰
                    nodes.remove(last.key);}
                removeLast();//移除鏈表尾部並後移    
            }else{
                currentSize++;
            }
            
            node.key=key;
            node.value=value;
            move(node);
            nodes.put(key, node);
        }
    }
    
    //移動鏈表節點至頭部
    private void move(CacheNode cacheNode){
        if(cacheNode==head)
            return;
        //連接先後節點
        if(cacheNode.prev!=null)
            cacheNode.prev.next=cacheNode.next;
        if(cacheNode.next!=null)
            cacheNode.next.prev=cacheNode.prev;
        //頭尾節點
        if (last == cacheNode)
            last = cacheNode.prev;
        if (head != null) {
            cacheNode.next = head;
            head.prev = cacheNode;
        }
        //移動後的鏈表
        head = cacheNode;
        cacheNode.prev = null;
        //節點惟一的狀況
        if (last == null)
            last = head;
    }
    
    //移除指定緩存
    public void remove(int key){
        CacheNode cacheNode =  nodes.get(key);
        if (cacheNode != null) {
            if (cacheNode.prev != null) {
                cacheNode.prev.next = cacheNode.next;
            }
            if (cacheNode.next != null) {
                cacheNode.next.prev = cacheNode.prev;
            }
            if (last == cacheNode)
                last = cacheNode.prev;
            if (head == cacheNode)
                head = cacheNode.next;
        }
        
    }
    //刪除尾部的結點,即去除最近最久未使用數據
    private void removeLast(){
        if(last!=null){
            if(last.prev!=null){
                last.prev.next=null;                
            }else{//空間大小爲1的狀況
                head = null;                
            }
            last = last.prev;
        }
    }
    
    public void clear() {
        head = null;
        last = null;
    }
    //測試用例
//    public static void main(String[] args){
//        LRUCache lCache=new LRUCache(2);
//        lCache.set(2, 1);
//        lCache.set(1, 1);
//        lCache.set(2, 3);
//        lCache.set(4, 1);
//        System.out.println(lCache.get(1));
//        System.out.println(lCache.get(2));
//        
//    }

}
複製代碼

 下面是提交中遇到的幾組測試用例:

複製代碼
Input:    2,[get(2),set(2,6),get(1),set(1,5),set(1,2),get(1),get(2)]
Expected:    [-1,-1,2,6]
Input: 2,[set(2,1),set(1,1),set(2,3),set(4,1),get(1),get(2)] Expected: [-1,3]
Input: 1,[get(0)] Expected: [-1]
複製代碼

 

同步:http://www.cnblogs.com/binyue/

 

LinkedHashMap 最遠未被使用丟棄緩存算法Least Recently used

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: https://blog.csdn.net/chou_qi/article/details/84718012
直接貼代碼

類:Test 
類: LeastRecentlyUsedLinkedHashMap<K,V> 


import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
public class Test {
public static void main(String[] args) {
/**
* LinkedHashMap 實現了Least Recently used 最遠未被使用丟棄緩存算法
* :在固定大小的LinkedHashMap中若是容量大於了 size() 將丟棄最遠時間未被使用的key value 是一種緩存算法
*/

LeastRecentlyUsedLinkedHashMap<String, String> lruMap = new 
LeastRecentlyUsedLinkedHashMap<String, String>(5);
lruMap.put("1", "a");
lruMap.put("2", "ab");
lruMap.put("3", "abc");
lruMap.put("4", "abcd");
lruMap.put("5", "abcde");
lruMap.put("6", "abcdef");
lruMap.put("7", "abcdefg");

printMapContent(lruMap);

System.out.println("\n");
lruMap.get("3");
printMapContent(lruMap);

System.out.println("\n");
lruMap.put("8", "xxxxxx");
printMapContent(lruMap);

}

/**
* map循環
* @param lruMap
*/
public static void printMapContent(LeastRecentlyUsedLinkedHashMap lruMap){

Set<Map.Entry<String,String>> entrySet = lruMap.entrySet();

Iterator iter = entrySet.iterator();

Map.Entry<String,String> entry = null;

while(iter.hasNext()){
entry = (Entry<String, String>) iter.next();
System.out.println("key: " + entry.getKey()+" value: " +entry.getValue());
}
}
}


LRU算法實現類:


public class LeastRecentlyUsedLinkedHashMap<K,V> extends LinkedHashMap<K,V> {

/**

*/
private static final long serialVersionUID = 1L;

/*指定map規定緩存容器長度*/
private int capacity;

LeastRecentlyUsedLinkedHashMap(int capacity){
super(capacity,0.75f,true);
this.capacity = capacity;
}


protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size()> capacity;
}

}
 

LRU緩存介紹與實現 (Java)

引子:

咱們平時總會有一個電話本記錄全部朋友的電話,可是,若是有朋友常常聯繫,那些朋友的電話號碼不用翻電話本咱們也能記住,可是,若是長時間沒有聯繫了,要再次聯繫那位朋友的時候,咱們又不得不求助電話本,可是,經過電話本查找仍是很費時間的。可是,咱們大腦可以記住的東西是必定的,咱們只能記住本身最熟悉的,而長時間不熟悉的天然就忘記了。

其實,計算機也用到了一樣的一個概念,咱們用緩存來存放之前讀取的數據,而不是直接丟掉,這樣,再次讀取的時候,能夠直接在緩存裏面取,而不用再從新查找一遍,這樣系統的反應能力會有很大提升。可是,當咱們讀取的個數特別大的時候,咱們不可能把全部已經讀取的數據都放在緩存裏,畢竟內存大小是必定的,咱們通常把最近常讀取的放在緩存裏(至關於咱們把最近聯繫的朋友的姓名和電話放在大腦裏同樣)。如今,咱們就來研究這樣一種緩存機制。

LRU緩存:

LRU緩存利用了這樣的一種思想。LRU是Least Recently Used 的縮寫,翻譯過來就是「最近最少使用」,也就是說,LRU緩存把最近最少使用的數據移除,讓給最新讀取的數據。而每每最常讀取的,也是讀取次數最多的,因此,利用LRU緩存,咱們可以提升系統的performance.

實現:

要實現LRU緩存,咱們首先要用到一個類 LinkedHashMap。 用這個類有兩大好處:一是它自己已經實現了按照訪問順序的存儲,也就是說,最近讀取的會放在最前面,最最不常讀取的會放在最後(固然,它也能夠實現按照插入順序存儲)。第二,LinkedHashMap自己有一個方法用於判斷是否須要移除最不常讀取的數,可是,原始方法默認不須要移除(這是,LinkedHashMap至關於一個linkedlist),因此,咱們須要override這樣一個方法,使得當緩存裏存放的數據個數超過規定個數後,就把最不經常使用的移除掉。LinkedHashMap的API寫得很清楚,推薦你們能夠先讀一下。

要基於LinkedHashMap來實現LRU緩存,咱們能夠選擇inheritance, 也能夠選擇 delegation, 我更喜歡delegation。基於delegation的實現已經有人寫出來了,並且寫得很漂亮,我就不班門弄斧了。代碼以下:

 

[java]  view plain copy
 
 
 
  1. import java.util.LinkedHashMap;  
  2. import java.util.Collection;  
  3. import java.util.Map;  
  4. import java.util.ArrayList;  
  5.   
  6. /** 
  7. * An LRU cache, based on <code>LinkedHashMap</code>. 
  8. * <p> 
  9. * This cache has a fixed maximum number of elements (<code>cacheSize</code>). 
  10. * If the cache is full and another entry is added, the LRU (least recently used) entry is dropped. 
  11. * <p> 
  12. * This class is thread-safe. All methods of this class are synchronized. 
  13. * <p> 
  14. * Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br> 
  15. * Multi-licensed: EPL / LGPL / GPL / AL / BSD. 
  16. */  
  17. public class LRUCache<K,V> {  
  18.   
  19. private static final float   hashTableLoadFactor = 0.75f;  
  20.   
  21. private LinkedHashMap<K,V>   map;  
  22. private int                  cacheSize;  
  23.   
  24. /** 
  25. * Creates a new LRU cache. 
  26. * @param cacheSize the maximum number of entries that will be kept in this cache. 
  27. */  
  28. public LRUCache (int cacheSize) {  
  29.    this.cacheSize = cacheSize;  
  30.    int hashTableCapacity = (int)Math.ceil(cacheSize / hashTableLoadFactor) + 1;  
  31.    map = new LinkedHashMap<K,V>(hashTableCapacity, hashTableLoadFactor, true) {  
  32.       // (an anonymous inner class)  
  33.       private static final long serialVersionUID = 1;  
  34.       @Override protected boolean removeEldestEntry (Map.Entry<K,V> eldest) {  
  35.          return size() > LRUCache.this.cacheSize; }}; }  
  36.   
  37. /** 
  38. * Retrieves an entry from the cache.<br> 
  39. * The retrieved entry becomes the MRU (most recently used) entry. 
  40. * @param key the key whose associated value is to be returned. 
  41. * @return    the value associated to this key, or null if no value with this key exists in the cache. 
  42. */  
  43. public synchronized V get (K key) {  
  44.    return map.get(key); }  
  45.   
  46. /** 
  47. * Adds an entry to this cache. 
  48. * The new entry becomes the MRU (most recently used) entry. 
  49. * If an entry with the specified key already exists in the cache, it is replaced by the new entry. 
  50. * If the cache is full, the LRU (least recently used) entry is removed from the cache. 
  51. * @param key    the key with which the specified value is to be associated. 
  52. * @param value  a value to be associated with the specified key. 
  53. */  
  54. public synchronized void put (K key, V value) {  
  55.    map.put (key, value); }  
  56.   
  57. /** 
  58. * Clears the cache. 
  59. */  
  60. public synchronized void clear() {  
  61.    map.clear(); }  
  62.   
  63. /** 
  64. * Returns the number of used entries in the cache. 
  65. * @return the number of entries currently in the cache. 
  66. */  
  67. public synchronized int usedEntries() {  
  68.    return map.size(); }  
  69.   
  70. /** 
  71. * Returns a <code>Collection</code> that contains a copy of all cache entries. 
  72. * @return a <code>Collection</code> with a copy of the cache content. 
  73. */  
  74. public synchronized Collection<Map.Entry<K,V>> getAll() {  
  75.    return new ArrayList<Map.Entry<K,V>>(map.entrySet()); }  
  76.   
  77. // end class LRUCache  
  78. ------------------------------------------------------------------------------------------  
  79. // Test routine for the LRUCache class.  
  80. public static void main (String[] args) {  
  81.    LRUCache<String,String> c = new LRUCache<String, String>(3);  
  82.    c.put ("1", "one");                           // 1  
  83.    c.put ("2", "two");                           // 2 1  
  84.    c.put ("3", "three");                         // 3 2 1  
  85.    c.put ("4", "four");                          // 4 3 2  
  86.    if (c.get("2") == null) throw new Error();    // 2 4 3  
  87.    c.put ("5", "five");                          // 5 2 4  
  88.    c.put ("4", "second four");                   // 4 5 2  
  89.    // Verify cache content.  
  90.    if (c.usedEntries() != 3)              throw new Error();  
  91.    if (!c.get("4").equals("second four")) throw new Error();  
  92.    if (!c.get("5").equals("five"))        throw new Error();  
  93.    if (!c.get("2").equals("two"))         throw new Error();  
  94.    // List cache content.  
  95.    for (Map.Entry<String, String> e : c.getAll())  
  96.       System.out.println (e.getKey() + " : " + e.getValue()); }  

代碼出自: http://www.source-code.biz/snippets/java/6.htm

 


在博客 http://gogole.iteye.com/blog/692103 裏,做者使用的是雙鏈表 + hashtable 的方式實現的。若是在面試題裏考到如何實現LRU,考官通常會要求使用雙鏈表 + hashtable 的方式。 因此,我把原文的部份內容摘抄以下:

 

雙鏈表 + hashtable實現原理:

將Cache的全部位置都用雙連錶鏈接起來,當一個位置被命中以後,就將經過調整鏈表的指向,將該位置調整到鏈表頭的位置,新加入的Cache直接加到鏈表頭中。這樣,在屢次進行Cache操做後,最近被命中的,就會被向鏈表頭方向移動,而沒有命中的,而想鏈表後面移動,鏈表尾則表示最近最少使用的Cache。當須要替換內容時候,鏈表的最後位置就是最少被命中的位置,咱們只須要淘汰鏈表最後的部分便可。

 

[java]  view plain copy
 
 
 
  1. public class LRUCache {  
  2.       
  3.     private int cacheSize;  
  4.     private Hashtable<Object, Entry> nodes;//緩存容器  
  5.     private int currentSize;  
  6.     private Entry first;//鏈表頭  
  7.     private Entry last;//鏈表尾  
  8.       
  9.     public LRUCache(int i) {  
  10.         currentSize = 0;  
  11.         cacheSize = i;  
  12.         nodes = new Hashtable<Object, Entry>(i);//緩存容器  
  13.     }  
  14.       
  15.     /** 
  16.      * 獲取緩存中對象,並把它放在最前面 
  17.      */  
  18.     public Entry get(Object key) {  
  19.         Entry node = nodes.get(key);  
  20.         if (node != null) {  
  21.             moveToHead(node);  
  22.             return node;  
  23.         } else {  
  24.             return null;  
  25.         }  
  26.     }  
  27.       
  28.     /** 
  29.      * 添加 entry到hashtable, 並把entry  
  30.      */  
  31.     public void put(Object key, Object value) {  
  32.         //先查看hashtable是否存在該entry, 若是存在,則只更新其value  
  33.         Entry node = nodes.get(key);  
  34.           
  35.         if (node == null) {  
  36.             //緩存容器是否已經超過大小.  
  37.             if (currentSize >= cacheSize) {  
  38.                 nodes.remove(last.key);  
  39.                 removeLast();  
  40.             } else {  
  41.                 currentSize++;  
  42.             }             
  43.             node = new Entry();  
  44.         }  
  45.         node.value = value;  
  46.         //將最新使用的節點放到鏈表頭,表示最新使用的.  
  47.         moveToHead(node);  
  48.         nodes.put(key, node);  
  49.     }  
  50.   
  51.     /** 
  52.      * 將entry刪除, 注意:刪除操做只有在cache滿了纔會被執行 
  53.      */  
  54.     public void remove(Object key) {  
  55.         Entry node = nodes.get(key);  
  56.         //在鏈表中刪除  
  57.         if (node != null) {  
  58.             if (node.prev != null) {  
  59.                 node.prev.next = node.next;  
  60.             }  
  61.             if (node.next != null) {  
  62.                 node.next.prev = node.prev;  
  63.             }  
  64.             if (last == node)  
  65.                 last = node.prev;  
  66.             if (first == node)  
  67.                 first = node.next;  
  68.         }  
  69.         //在hashtable中刪除  
  70.         nodes.remove(key);  
  71.     }  
  72.   
  73.     /** 
  74.      * 刪除鏈表尾部節點,即便用最後 使用的entry 
  75.      */  
  76.     private void removeLast() {  
  77.         //鏈表尾不爲空,則將鏈表尾指向null. 刪除連表尾(刪除最少使用的緩存對象)  
  78.         if (last != null) {  
  79.             if (last.prev != null)  
  80.                 last.prev.next = null;  
  81.             else  
  82.                 first = null;  
  83.             last = last.prev;  
  84.         }  
  85.     }  
  86.       
  87.     /** 
  88.      * 移動到鏈表頭,表示這個節點是最新使用過的 
  89.      */  
  90.     private void moveToHead(Entry node) {  
  91.         if (node == first)  
  92.             return;  
  93.         if (node.prev != null)  
  94.             node.prev.next = node.next;  
  95.         if (node.next != null)  
  96.             node.next.prev = node.prev;  
  97.         if (last == node)  
  98.             last = node.prev;  
  99.         if (first != null) {  
  100.             node.next = first;  
  101.             first.prev = node;  
  102.         }  
  103.         first = node;  
  104.         node.prev = null;  
  105.         if (last == null)  
  106.             last = first;  
  107.     }  
  108.     /* 
  109.      * 清空緩存 
  110.      */  
  111.     public void clear() {  
  112.         first = null;  
  113.         last = null;  
  114.         currentSize = 0;  
  115.     }  
  116.   
  117. }  
  118.   
  119. class Entry {  
  120.     Entry prev;//前一節點  
  121.     Entry next;//後一節點  
  122.     Object value;//值  
  123.     Object key;//鍵  
  124. leetcode 146. LRU Cache 鏈表操做與緩存處理

    版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
    本文連接: https://blog.csdn.net/chengdezhi2011/article/details/76762623

     

     

     

    1.  
      public class LRUCache {
    2.  
      class DlinkedNote{
    3.  
      int key;
    4.  
      int value;
    5.  
      DlinkedNote pre;
    6.  
      DlinkedNote post;
    7.  
      DlinkedNote(){}
    8.  
      DlinkedNote( int key, int value){
    9.  
      this.key = key;
    10.  
      this. value = value;
    11.  
      }
    12.  
      }
    13.  
       
    14.  
      HashMap<Integer, DlinkedNote> cache = new HashMap<Integer, DlinkedNote>();
    15.  
      int capacity;
    16.  
      DlinkedNote head;
    17.  
      DlinkedNote tail;
    18.  
       
    19.  
       
    20.  
      public DlinkedNote poptail(){
    21.  
      DlinkedNote res = tail.pre;
    22.  
      removenode(res);
    23.  
      return res;
    24.  
      }
    25.  
       
    26.  
      public void movetohead(DlinkedNote node){
    27.  
      removenode(node);
    28.  
      addnode(node);
    29.  
      }
    30.  
       
    31.  
      public void removenode(DlinkedNote node){
    32.  
      DlinkedNote pre = node.pre;
    33.  
      DlinkedNote post = node.post;
    34.  
      pre.post = post;
    35.  
      post.pre = pre;
    36.  
      }
    37.  
       
    38.  
      /** always add at the head of link*/
    39.  
      public void addnode(DlinkedNote node){
    40.  
      DlinkedNote cur_first = this.head.post;
    41.  
      cur_first.pre = node;
    42.  
      node.post = cur_first;
    43.  
      node.pre = this.head;
    44.  
      this.head.post = node;
    45.  
      }
    46.  
       
    47.  
      public LRUCache(int capacity) {
    48.  
      DlinkedNote head = new DlinkedNote();
    49.  
      DlinkedNote tail = new DlinkedNote();
    50.  
      head.post = tail;
    51.  
      tail.pre = head;
    52.  
      this.head = head;
    53.  
      this.tail = tail;
    54.  
      this.capacity = capacity;
    55.  
      // this.count = 0;
    56.  
      }
    57.  
       
    58.  
      public int get(int key) {
    59.  
      DlinkedNote res = cache. get(key);
    60.  
      if(res== null){
    61.  
      return -1;
    62.  
      }
    63.  
      movetohead(res);
    64.  
      return res. value;
    65.  
      }
    66.  
       
    67.  
      public void put(int key, int value) {
    68.  
      DlinkedNote node = cache. get(key);
    69.  
      int count = cache.size();
    70.  
      if(node== null){
    71.  
      DlinkedNote new_node = new DlinkedNote(key, value);
    72.  
      this.cache.put(key, new_node);
    73.  
      addnode(new_node);
    74.  
      count++;
    75.  
      // while(count>this.capacity)
    76.  
      if(count> this.capacity){
    77.  
      DlinkedNote last = this.poptail();
    78.  
      cache. remove(last.key);
    79.  
      }
    80.  
      } else{
    81.  
      if(node. value!= value){
    82.  
      node. value = value;
    83.  
      }
    84.  
      movetohead(node);
    85.  
      }
    86.  
      }
    87.  

leetcode 146. LRU Cache 鏈表操做與緩存處理

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接: https://blog.csdn.net/chengdezhi2011/article/details/76762623

 

 

 

  1.  
    public class LRUCache {
  2.  
    class DlinkedNote{
  3.  
    int key;
  4.  
    int value;
  5.  
    DlinkedNote pre;
  6.  
    DlinkedNote post;
  7.  
    DlinkedNote(){}
  8.  
    DlinkedNote( int key, int value){
  9.  
    this.key = key;
  10.  
    this. value = value;
  11.  
    }
  12.  
    }
  13.  
     
  14.  
    HashMap<Integer, DlinkedNote> cache = new HashMap<Integer, DlinkedNote>();
  15.  
    int capacity;
  16.  
    DlinkedNote head;
  17.  
    DlinkedNote tail;
  18.  
     
  19.  
     
  20.  
    public DlinkedNote poptail(){
  21.  
    DlinkedNote res = tail.pre;
  22.  
    removenode(res);
  23.  
    return res;
  24.  
    }
  25.  
     
  26.  
    public void movetohead(DlinkedNote node){
  27.  
    removenode(node);
  28.  
    addnode(node);
  29.  
    }
  30.  
     
  31.  
    public void removenode(DlinkedNote node){
  32.  
    DlinkedNote pre = node.pre;
  33.  
    DlinkedNote post = node.post;
  34.  
    pre.post = post;
  35.  
    post.pre = pre;
  36.  
    }
  37.  
     
  38.  
    /** always add at the head of link*/
  39.  
    public void addnode(DlinkedNote node){
  40.  
    DlinkedNote cur_first = this.head.post;
  41.  
    cur_first.pre = node;
  42.  
    node.post = cur_first;
  43.  
    node.pre = this.head;
  44.  
    this.head.post = node;
  45.  
    }
  46.  
     
  47.  
    public LRUCache(int capacity) {
  48.  
    DlinkedNote head = new DlinkedNote();
  49.  
    DlinkedNote tail = new DlinkedNote();
  50.  
    head.post = tail;
  51.  
    tail.pre = head;
  52.  
    this.head = head;
  53.  
    this.tail = tail;
  54.  
    this.capacity = capacity;
  55.  
    // this.count = 0;
  56.  
    }
  57.  
     
  58.  
    public int get(int key) {
  59.  
    DlinkedNote res = cache. get(key);
  60.  
    if(res== null){
  61.  
    return -1;
  62.  
    }
  63.  
    movetohead(res);
  64.  
    return res. value;
  65.  
    }
  66.  
     
  67.  
    public void put(int key, int value) {
  68.  
    DlinkedNote node = cache. get(key);
  69.  
    int count = cache.size();
  70.  
    if(node== null){
  71.  
    DlinkedNote new_node = new DlinkedNote(key, value);
  72.  
    this.cache.put(key, new_node);
  73.  
    addnode(new_node);
  74.  
    count++;
  75.  
    // while(count>this.capacity)
  76.  
    if(count> this.capacity){
  77.  
    DlinkedNote last = this.poptail();
  78.  
    cache. remove(last.key);
  79.  
    }
  80.  
    } else{
  81.  
    if(node. value!= value){
  82.  
    node. value = value;
  83.  
    }
  84.  
    movetohead(node);
  85.  
    }
  86.  
    }
相關文章
相關標籤/搜索