随笔- 509  文章- 0  评论- 151  阅读- 22万 

LRU Cache

2014.2.13 18:15

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.

Solution:

  My LRU cache is made up of two parts, a hash table and a double-linked list.

  Hash table provides O(1) access to every element in the cache. Double-linked list allows you to move a node to the head or to the tail in O(1) time, although you'll need O(n) time locating this node. With their combiantion, both process can reach O(1) complexity.

  The double-linked list is handwritten, while the hash table is unordered_map from new STL.

  It's quite easy to make mistake on linked list, especially when it is double-linked.

  Whenever set() or get() is called, the node visitied or created should be put on the front of the list.

  Time complexity is O(1) for both set() and get(), linked list and hashing both use O(n) space.

Accepted code:

复制代码
  1 // 1WA, 1AC, double-linked list + unordered_map
  2 #include <unordered_map>
  3 using  namespace std;
  4 
  5 typedef struct DoubleLinkedListNode{
  6 public:
  7     int key;
  8     int value;
  9     struct DoubleLinkedListNode *left;
 10     struct DoubleLinkedListNode *right;
 11     DoubleLinkedListNode(int _key = 0, int _value = 0): key(_key), value(_value), left(nullptr), right(nullptr) {}
 12 }DoubleLinkedListNode;
 13 
 14 class LRUCache{
 15 public:
 16     LRUCache(int capacity) {
 17         this->capacity = capacity;
 18         this->size = 0;
 19         this->head = this->tail = nullptr;
 20         this->hash_table.clear();
 21     }
 22     
 23     int get(int key) {
 24         if (size == 0) {
 25             // the LRU cache is empty.
 26             return KEY_NOT_FOUND;
 27         }
 28         
 29         unordered_map<int, DoubleLinkedListNode *>::iterator mit;
 30         
 31         mit = hash_table.find(key);
 32         if (mit != hash_table.end()) {
 33             // the key exists in the cache.
 34             DoubleLinkedListNode *ptr = mit->second;
 35             if (ptr == head) {
 36                 // do nothing
 37             } else if (ptr == tail) {
 38                 // ptr is the tail node.
 39                 tail = ptr->left;
 40                 tail->right = nullptr;
 41                 ptr->left = nullptr;
 42                 ptr->right = head;
 43                 head->left = ptr;
 44                 head = ptr;
 45             } else {
 46                 // ptr is at middle of the list.
 47                 DoubleLinkedListNode *ptr1, *ptr2;
 48                 ptr1 = ptr->left;
 49                 ptr2 = ptr->right;
 50                 ptr1->right = ptr2;
 51                 ptr2->left = ptr1;
 52                 ptr->left = nullptr;
 53                 ptr->right = head;
 54                 head->left = ptr;
 55                 head = ptr;
 56             }
 57             return ptr->value;
 58         } else {
 59             // key not found.
 60             return KEY_NOT_FOUND;
 61         }
 62     }
 63     
 64     void set(int key, int value) {
 65         if (capacity == 0) {
 66             // no room to place anything.
 67             return;
 68         }
 69         
 70         unordered_map<int, DoubleLinkedListNode *>::iterator mit;
 71         mit = hash_table.find(key);
 72         if (mit != hash_table.end()) {
 73             // the key exists in the cache.
 74             DoubleLinkedListNode *ptr = mit->second;
 75             if (ptr == head) {
 76                 // do nothing
 77             } else if (ptr == tail) {
 78                 // ptr is the tail node.
 79                 tail = ptr->left;
 80                 tail->right = nullptr;
 81                 ptr->left = nullptr;
 82                 ptr->right = head;
 83                 head->left = ptr;
 84                 head = ptr;
 85             } else {
 86                 // ptr is at middle of the list.
 87                 DoubleLinkedListNode *ptr1, *ptr2;
 88                 ptr1 = ptr->left;
 89                 ptr2 = ptr->right;
 90                 ptr1->right = ptr2;
 91                 ptr2->left = ptr1;
 92                 ptr->left = nullptr;
 93                 ptr->right = head;
 94                 head->left = ptr;
 95                 head = ptr;
 96             }
 97             ptr->value = value;
 98         } else {
 99             DoubleLinkedListNode *ptr = nullptr;
100             if (size < capacity) {
101                 // still some space left.
102                 // put the new item at front, not rear.
103                 ptr = new DoubleLinkedListNode(key, value);
104                 if (head != nullptr) {
105                     head->left = ptr;
106                     ptr->right = head;
107                 } else {
108                     tail = ptr;
109                 }
110                 head = ptr;
111                 hash_table[key] = ptr;
112                 ++size;
113             } else {
114                 // capacity is reached.
115                 ptr = tail;
116                 hash_table.erase(tail->key);
117                 ptr->key = key;
118                 ptr->value = value;
119                 if (head != tail) {
120                     tail = ptr->left;
121                     tail->right = nullptr;
122                     ptr->left = nullptr;
123                     ptr->right = head;
124                     head->left = ptr;
125                     head = ptr;
126                 }
127                 hash_table[key] = ptr;
128             }
129         }
130     }
131 private:
132     static const int KEY_NOT_FOUND = -1;
133     int capacity;
134     int size;
135     DoubleLinkedListNode *head;
136     DoubleLinkedListNode *tail;
137     unordered_map<int, DoubleLinkedListNode *> hash_table;
138 };
复制代码

 

 posted on   zhuli19901106  阅读(226)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示