LRU是Least Recently Used的縮寫,意思是最近最少使用,它是一種Cache替換算法。如今要設計一種數據結構有以下幾種性質:算法
1. 每一個節點爲一對key,value的形式,可經過get <key>查找,經過put <key, value> 插入數據結構
2. 最大存儲節點數爲nide
3. put操做時,若是已經存儲了n個節點,則要淘汰最近最少使用的那個節點性能
可能會有不少種解決方案,例如:優化
1、用一個雙向鏈表來存儲全部節點,get時,遍歷整個鏈表,找到對應的節點,而且把該節點挪動到鏈表的第一個位置,所以,連接中越靠前的位置老是距離最後一次訪問時間越短的節點,越靠後的位置老是距離最後一次訪問時間約久的節點。因此put時,若是已達到最大存儲節點數時,直接刪除鏈表最後一個節點再插入便可。總結,優勢:實現簡單,put操做的時間複雜度爲O(1) 缺點:get操做時間複雜度爲O(n),不夠優秀。this
2、咱們都知道哈希表這種數據結構查詢的時間性能很好,可是在這裏若是隻用一個哈希表,雖然查詢和插入操做都能優化到O(1),可是在刪除,也就是查找最近最少使用的節點時,卻不得不遍歷整個哈希表。咱們來作進一步優化,前面第一種方案刪除和插入操做都是O(1)的,可是查詢操做是O(n),若是能把這兩種方案結合一下的話,三種操做不就都是O(1)時間複雜度了。怎麼結合呢?spa
哈希表的value存儲節點的指針,同時把全部的value鏈接成一個雙向鏈表,查詢操做時,經過哈希表直接找到這個節點的指針,同時,能夠在O(1)時間將這個節點移動到鏈表頭部,刪除操做時,直接刪除鏈表尾部那個節點,同時將這個節點從哈希表中刪除。設計
C++實現(這裏爲了簡化操做,直接用了STL的map代替哈希表)指針
class LRUCache { public: struct Node { int key, value; Node *next, *pre; }; map<int, Node*> cache; Node *head, *rear; int size; LRUCache(int capacity) { size = capacity; head = new Node(); rear = new Node(); head->pre = NULL; head->next = rear; rear->next = NULL; rear->pre = head; } int get(int key) { if(cache.find(key) == cache.end()) return -1; Node *tmp = cache[key]; tmp->pre->next = tmp->next; tmp->next->pre = tmp->pre; head->next->pre = tmp; tmp->next = head->next; tmp->pre = head; head->next = tmp; return tmp->value; } void lru_delete() { if(cache.size() == 0) return; Node* tmp = rear->pre; rear->pre = tmp->pre; tmp->pre->next = rear; cache.erase(tmp->key); delete tmp; } void put(int key, int value) { // if the key exist, then just update the value if(cache.find(key) != cache.end()) { cache[key]->value = value; this->get(key); return; } if(cache.size() >= this->size) this->lru_delete(); Node *tmp = new Node; tmp->key = key; tmp->value = value; tmp->pre = this->head; tmp->next = this->head->next; if(head->next != NULL) head->next->pre = tmp; this->head->next = tmp; cache.insert(pair<int, Node*>(key, tmp)); } };