【算法33】LRU算法


題目來源

LeetCode: https://leetcode.com/problems/lru-cache/

LRU簡介

LRU (Least Recently Used,最近最少使用)算法是操作系統中一種經典的頁面置換算法,當發生缺頁中斷時,需要將內存的一個或幾個頁面換出,LRU指出應該將內存最近最少使用的那些頁面進行換出,依據的是程序的局部性原理,最近經常使用的頁面在不久的將來也很有可能被使用,反之最近很少使用的頁面未來也不太可能再使用。

LRU 數據結構

LRU采用雙向鏈表+hash表的數據結構實現,雙向鏈表作為隊列存儲當前緩存節點,其中從表頭到表尾的元素按照最近使用的時間進行排列,放在表頭的是最近剛剛被使用過的元素,表尾的最近最少使用的元素;如果僅僅采用雙向鏈表,那么查詢某個元素需要 O(n) 的時間,為了加快雙向鏈表中元素的查詢速度,采用hash表講key進行映射,可以在O(1)的時間內找到需要節點。

LRU主要實現以下兩個接口:

int Get(int key);
void Put(int key, int value);

其中 Get 用來讀取隊列中的元素,同時需要將該元素移動到表頭;Put 用來向隊列中插入元素。

LRU 具體實現

從實現的角度來看,每次 Get 時, 需要判斷該 key 是否在隊列中,如果不在,返回-1;如果在,需要重新移動該元素到表頭位置(具體實現,可以先刪除,在插入到表頭)。 每次 Put 時,首先需要判斷key是否在隊列中,如果在,那么更新其 value值,然后移動該元素到表頭即可;如果不在,需要進一步判斷,隊列是否已滿,如果已滿;那么需要首先刪除隊尾元素,並對 size - 1, 刪除哈希表中對應元素的 key;然后在插入新的元素到隊頭。

具體C++代碼如下:

  1 /**
  2  * LRU Cache Implementation using DoubleLinkList & hashtable
  3  * Copyright 2015 python27
  4  * 2015/06/26
  5  */
  6 #include <iostream>
  7 #include <string>
  8 #include <map>
  9 #include <list>
 10 #include <deque>
 11 #include <cassert>
 12 #include <cstdio>
 13 #include <cstdlib>
 14 using namespace std;
 15 
 16 struct CacheNode
 17 {
 18     int key;
 19     int value;
 20     CacheNode* prev;
 21     CacheNode* next;
 22     
 23     CacheNode(int k, int v) : key(k), value(v), prev(NULL), next(NULL)
 24     {}
 25     
 26     CacheNode():key(0), value(0), prev(NULL), next(NULL)
 27     {}        
 28 };
 29 
 30 class LRUCache
 31 {
 32 public:
 33     LRUCache(int capacity);
 34     
 35     int Get(int key);
 36     void Put(int key, int value);
 37     
 38 public:
 39     void PrintList() const;
 40 private:
 41     void InsertNodeFront(CacheNode* p);
 42     void DeleteNode(CacheNode* p);
 43     
 44 private:
 45     map<int, CacheNode*> m_hashtable;        // hash table
 46     CacheNode* m_head;                        // double link list head
 47     CacheNode* m_tail;                        // double link list tail
 48     int m_capacity;                            // capacity of link list
 49     int m_size;                                // current size of link list
 50 };
 51 
 52 void LRUCache::PrintList() const
 53 {
 54     CacheNode* p = m_head;
 55     for (p = m_head; p != NULL; p = p->next)
 56     {
 57         printf("(%d, %d)->", p->key, p->value);
 58     }
 59     printf("\n");
 60     printf("size = %d\n", m_size);
 61     printf("capacity = %d\n", m_capacity);
 62 }
 63 
 64 LRUCache::LRUCache(int capacity)
 65 {
 66     m_capacity = capacity;
 67     m_size = 0;
 68     m_head = NULL;
 69     m_tail = NULL;
 70 }
 71 
 72 //    insert node into head pointed by p
 73 void LRUCache::InsertNodeFront(CacheNode* p)
 74 {
 75     if (p == NULL) return;
 76     
 77     if (m_head == NULL)
 78     {
 79         m_head = p;
 80         m_tail = p;
 81     }
 82     else
 83     {        
 84         p->next = m_head;
 85         m_head->prev = p;
 86         m_head = p;
 87     }
 88 }
 89 
 90 // delete node in double linklist pointed by p
 91 void LRUCache::DeleteNode(CacheNode* p)
 92 {
 93     if (p == NULL) return;
 94     
 95     assert(m_head != NULL && m_tail != NULL);
 96     
 97     if (m_size == 1)
 98     {
 99         if (p == m_head && p == m_tail)
100         {
101             delete p;
102             m_head = NULL;
103             m_tail = NULL;
104         }
105         else
106         {
107             fprintf(stderr, "Delete Wrong! No such Node");
108             return;
109         }
110     }
111     else if (p == m_head)
112     {
113         m_head = m_head->next;
114         m_head->prev = NULL;
115         delete p;
116     }
117     else if (p == m_tail)
118     {
119         m_tail = m_tail->prev;
120         m_tail->next = NULL;
121         delete p;
122     }
123     else
124     {
125         p->prev->next = p->next;
126         p->next->prev = p->prev;
127         delete p;
128     }
129     
130 }
131 
132 int LRUCache::Get(int key)
133 {
134     // if key not in return -1
135     if (m_hashtable.find(key) == m_hashtable.end())
136     {
137         return -1;
138     }
139         
140     CacheNode* p = m_hashtable[key];
141     int k = p->key;
142     int v = p->value;
143     
144     // delete this node
145     DeleteNode(p);
146         
147     // insert this node to the head
148     p = new CacheNode(k, v);
149     InsertNodeFront(p);
150     // update hash table
151     m_hashtable[k] = p;
152     return p->value;
153 }
154 
155 void LRUCache::Put(int key, int value)
156 {
157     // if key alread in, update
158     if (m_hashtable.find(key) != m_hashtable.end())
159     {
160         CacheNode* p = m_hashtable[key];
161         
162         // delete node
163         DeleteNode(p);
164         // insert node
165         p = new CacheNode(key, value);
166         InsertNodeFront(p);
167         // update hash table
168         m_hashtable[key] = p;
169         return;
170     }
171     // if list is full, delete the tail node
172     else if (m_size >= m_capacity)
173     {
174         // delete the tail node
175         CacheNode* p = m_tail;
176         m_hashtable.erase(p->key);
177         DeleteNode(p);
178         m_size--;
179     }
180     
181     // create node and insert into head
182     assert(m_size < m_capacity);
183     CacheNode* p = new CacheNode(key, value);
184     InsertNodeFront(p);
185     m_hashtable[key] = p;
186     m_size++;
187 }
188 
189 int main()
190 {
191     LRUCache lru(3);
192     lru.Put(1, 11);
193     lru.PrintList();
194     lru.Put(2, 22);
195     lru.PrintList();
196     lru.Put(3, 33);
197     lru.PrintList();
198     lru.Put(4, 44);
199     lru.PrintList();
200     int value = lru.Get(3);
201     printf("Get(3) = %d\n", value);
202     lru.PrintList();
203     value = lru.Get(2);
204     printf("Get(2) = %d\n", value);
205     lru.PrintList();
206     value = lru.Get(4);
207     printf("Get(4) = %d\n", value);
208     lru.PrintList();
209     value = lru.Get(1);
210     printf("Get(1) = %d\n", value);
211     lru.PrintList();
212     
213     return 0;
214 }

 


免責聲明!

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



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