操作系統-2-存儲管理之LRU頁面置換算法(LeetCode146)


LRU緩存機制

題目:運用你所掌握的數據結構,設計和實現一個  LRU (最近最少使用) 緩存機制。

   它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。

   獲取數據 get(key) - 如果密鑰 (key) 存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。

      寫入數據 put(key, value) - 如果密鑰已經存在,則變更其數據值;如果密鑰不存在,則插入該組「密鑰/數據值」。

   當緩存容量達到上限時,它應該在寫入新數據之前刪除最久未使用的數據值,從而為新的數據值留出空間。

示例:  
   LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );

   cache.put(1, 1);
   cache.put(2, 2);
   cache.get(1);       // 返回  1
   cache.put(3, 3);    // 該操作會使得密鑰 2 作廢
   cache.get(2);       // 返回 -1 (未找到)
   cache.put(4, 4);    // 該操作會使得密鑰 1 作廢
   cache.get(1);       // 返回 -1 (未找到)
   cache.get(3);       // 返回  3
   cache.get(4);       // 返回  4

代碼:

 1 class LRUCache {
 2 
 3     public LRUCache(int capacity) {
 4 
 5     }
 6     
 7     public int get(int key) {
 8 
 9     }
10     
11     public void put(int key, int value) {
12 
13     }
14 }
15 
16 /**
17  * Your LRUCache object will be instantiated and called as such:
18  * LRUCache obj = new LRUCache(capacity);
19  * int param_1 = obj.get(key);
20  * obj.put(key,value);
21  */

LRU頁面置換算法(最近最少使用算法)(我的另一篇博文講到了LFU最不經常使用頁面置換算法,可以進行比較)

  原理:

    選擇最后一次訪問時間距離當前時間最長的一頁並淘汰之。即淘汰沒有使用的時間最長的頁
    每頁設置訪問時間戳,每當頁面被訪問時,該頁面的時間戳被更新;
    發生缺頁中斷時,淘汰時間戳最小的頁面;

    如圖:圖中的頁面為三頁,依次向存儲中加入432143543215這些數字。

       而存儲空間只能存儲三個頁面,所以會按照上述規則不斷淘汰已經存儲在頁面中的數字。

    

解題思路(logN的思路):

    知道了LRU的置換規則后,由於此題需要存儲的是key和value,所以

      首先,需要建一個類node,存放三樣東西,key,value,times(時間戳)

      其次,選擇一種合適的數據結構來解決存儲優先級問題,此處我們采用內部是小頂堆的PriorityQueue優先級隊列用來實現times最小的元素在隊頭

         但是我們會在讓新元素入隊之前可能會刪除隊列中指定元素,當然可以去遍歷隊列,但是這樣太慢了

         我們可以再用一種HashMap的數據集合用來存儲節點,以便快速通過node的key來得到整個node。

      最后,便是處理邏輯關系,寫題目要求的get,put方法了

解題代碼詳解(logN):

 

 1 public class node implements Comparable<node>{
 2     private int Key;//
 3     private int Value;//
 4     private int Times;//時間戳
 5     node() {}
 6     node(int key, int value, int time) {
 7         this.Key = key;
 8         this.Value = value;
 9         this.Times = time;
10     }
11     public int getKey() {
12         return Key;
13     }
14 
15     public void setKey(int Key) {
16         this.Key = Key;
17     }
18 
19     public int getValue() {
20         return Value;
21     }
22 
23     public void setValue(int Value) {
24         this.Value = Value;
25     }
26 
27     public int getTimes() {
28         return Times;
29     }
30 
31     public void setTimes(int Times) {
32         this.Times = Times;
33     }
34 
35     @Override
36     public int compareTo(node o) {
37         //實現times最小的元素在隊頭
38         return Times - o.Times;
39     }
40 }
41 
42 class LRUCache {
43     PriorityQueue<node> KeyValueTimes = new PriorityQueue();//用於實現優先級順序
44     Map<Integer, node> nodeset;//用於O(1)取出某個具體的node
45     public int Capacity = 0;//我的cache中最大容量
46     public int nownum = 0;//cache的實時元素個數
47     public int tim = 0;//時間戳
48 
49     public LRUCache(int capacity) {
50         this.Capacity = capacity;//設置cache容量
51         nodeset = new HashMap<Integer, node>(capacity);//用於O(1)取出某個具體的node,容量依然設置為capacity
52     }
53     
54     public int get(int key) {
55         if(this.Capacity == 0)//判斷容量是否為空,為空則直接返回-1
56             return -1;
57         node nownode = nodeset.get(key);//通過HashMap,快速通過key鍵快速得到node
58         if (nownode == null) {//如果key這個鍵沒在隊列中,則返回-1
59             return -1;
60         }else{
61             KeyValueTimes.remove(nownode);//移除隊列中當前的這個node
62             nownode.setTimes(tim++);//更新當前這個node的時間戳
63             KeyValueTimes.offer(nownode);//再把它放回去
64         }
65         return nownode.getValue();
66     }
67     
68     public void put(int key, int value) {
69         if(this.Capacity == 0)//判斷容量是否為空,為空則不進行put
70             return;
71         node thisnode = new node(key,value,tim++);
72         node oldnode = nodeset.get(key);
73         if(oldnode == null){//隊列里不存在這個key
74             if(nownum < this.Capacity){//沒裝滿
75                 KeyValueTimes.offer(thisnode);//在隊列里添加新node
76                 nodeset.put(key,thisnode);//在HashMap里添加新node
77                 nownum++;//更新當前cache的元素個數
78             }
79             else{//裝滿了,需要LRU,最近最久為使用被移除
80                 nodeset.remove(KeyValueTimes.poll().getKey());//移除隊列里的隊頭,移除HashMap對應的那個node
81                 KeyValueTimes.offer(thisnode);//在隊列里添加新node
82                 nodeset.put(key,thisnode);//在HashMap里添加新node
83             }
84         }
85         else{//隊列里存在這個key
86             KeyValueTimes.remove(oldnode);//移除隊列里鍵為key的node,移除HashMap對應的那個node
87             nodeset.remove(oldnode.getKey());
88             KeyValueTimes.offer(thisnode);//在隊列里添加新node,這里新的node的value值可能會不一樣,所以更新了value
89             nodeset.put(key,thisnode);//在隊列里添加新node,這里新的node的value值可能會不一樣,所以更新了value
90         }
91     }
92 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM