赞
踩
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
[null, null, null, 1, null, -1, null, -1, 3, 4]
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
LRU缓存表需要实现如下两个操作:
LRU和LFU的区别:
当空间不足时,LRU算法优先删除最久未使用的key。而LFU算法是优先删除最少使用的key,如果有多个最少使用的key,则找出其中最久未使用的key删除。
LRU的实现原理:
LRU缓存结构可以基于哈希表map和双向链表link来实现。
这里哈希表map的值列 和 双向链表的节点 是共享Node的。如下图所示:
通过哈希表map的键列,我们可以快速判断key是否已存在于LRU缓存中。
由于map不存在key=1,因此当前put是新增操作,且由于map中记录键数量<capacity,即容量足够,因此无需执行逐出操作。
下面我需要创建节点 Node(key=1, val=1),并构建如下关系:
- map的键列插入key=1,并key=1的值列和 Node(key=1, val=1) 关联
- 将 Node(key=1, val=1) 头插入到双向链表Link 中(离链表头head越近,即为最近使用,离链表尾tail越近,即为最久未使用)
由于map不存在key=2的键,因此是put是新增操作,检查容量足够。
因此创建 Node(key=2, val=2) 后,构建如下关系。
由于map存在key=1的键,因此可以根据map[key=1]找到对应的节点Node(key=1, val=1),并获取Node.val返回。
另外,get操作会更新key=1为最近使用,因此我们需要将Node(key=1, val=1)暂时从Link中移除,然后头插到Link。
由于map不存在key=3的键,因此是put是新增操作,但是此时我们发现map中记录了两个键,分别为key=1,key=2,已经装满了capacity=2的LRU缓存表,因此put新增操作前需要先逐出最久未使用的key。
前面我们说明过,离Link链表头越近的节点,则为最近使用,离Link链表尾越近的节点,则为最久未使用。
因此 Link.tail.prev 节点即为最久未使用的节点,此时我们需要删除它:
- Link中删除该节点
- 根据节点的Node.key,找到map[Node.key]的键,并删除该键
删除最久未使用后,容量足够放下新节点Node(key=3, val=3)
以上即为LRU缓存的实现原理的图示。大家可以对照下面代码实现,继续想想后面的图示。
- import java.util.HashMap;
-
- class LRUCache {
- static class Node {
- int key;
- int val;
- Node prev;
- Node next;
-
- public Node() {};
- public Node(int key, int val) {
- this.key = key;
- this.val = val;
- }
- }
-
- static class Link {
- Node head;
- Node tail;
-
- public Link() {
- this.head = new Node();
- this.tail = new Node();
- this.head.next = this.tail;
- this.tail.prev = this.head;
- }
-
- public void removeNode(Node node) {
- node.prev.next = node.next;
- node.next.prev = node.prev;
- node.prev = null;
- node.next = null;
- }
-
- public void addFirst(Node node) {
- node.next = this.head.next;
- this.head.next.prev = node;
- this.head.next = node;
- node.prev = this.head;
- }
- }
-
- int capacity;
- Link link;
- HashMap<Integer, Node> map;
-
- public LRUCache(int capacity) {
- this.capacity = capacity;
- this.link = new Link();
- this.map = new HashMap<>();
- }
-
- public int get(int key) {
- if (this.map.containsKey(key)) {
- Node node = this.map.get(key);
-
- this.link.removeNode(node);
- this.link.addFirst(node);
-
- return node.val;
- } else {
- return -1;
- }
- }
-
- public void put(int key, int value) {
- if (this.map.containsKey(key)) {
- Node node = this.map.get(key);
- this.link.removeNode(node);
- this.link.addFirst(node);
- node.val = value;
- } else {
- if (this.map.size() == this.capacity) {
- Node removed = this.link.tail.prev;
- this.link.removeNode(removed);
- this.map.remove(removed.key);
- }
-
- Node newNode = new Node(key, value);
- this.link.addFirst(newNode);
- this.map.put(key, newNode);
- }
- }
- }
-
- //public class Main {
- // public static void main(String[] args) {
- // LRUCache lRUCache = new LRUCache(2);
- // lRUCache.put(1, 1); // 缓存是 {1=1}
- // lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
- // System.out.println(lRUCache.get(1)); // 返回 1
- // lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
- // System.out.println(lRUCache.get(2)); // 返回 -1 (未找到)
- // lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
- // System.out.println(lRUCache.get(1)); // 返回 -1 (未找到)
- // System.out.println(lRUCache.get(3)); // 返回 3
- // System.out.println(lRUCache.get(4)); // 返回 4
- // }
- //}
- class Node {
- constructor(key, val) {
- this.key = key;
- this.val = val;
- this.next = null;
- this.prev = null;
- }
- }
-
- class Link {
- constructor() {
- this.head = new Node();
- this.tail = new Node();
- this.head.next = this.tail;
- this.tail.prev = this.head;
- }
-
- removeNode(node) {
- node.prev.next = node.next;
- node.next.prev = node.prev;
- node.prev = null;
- node.next = null;
- }
-
- addFirst(node) {
- node.next = this.head.next;
- this.head.next.prev = node;
- this.head.next = node;
- node.prev = this.head;
- }
- }
-
- /**
- * @param {number} capacity
- */
- var LRUCache = function (capacity) {
- this.capacity = capacity;
- this.map = new Map();
- this.link = new Link();
- };
-
- /**
- * @param {number} key
- * @return {number}
- */
- LRUCache.prototype.get = function (key) {
- if (this.map.has(key)) {
- const node = this.map.get(key);
- this.link.removeNode(node);
- this.link.addFirst(node);
- return node.val;
- } else {
- return -1;
- }
- };
-
- /**
- * @param {number} key
- * @param {number} value
- * @return {void}
- */
- LRUCache.prototype.put = function (key, value) {
- if (this.map.has(key)) {
- const node = this.map.get(key);
- this.link.removeNode(node);
- this.link.addFirst(node);
- node.val = value;
- } else {
- if (this.map.size == this.capacity) {
- const removed = this.link.tail.prev;
- this.link.removeNode(removed);
- this.map.delete(removed.key);
- }
-
- const newNode = new Node(key, value);
- this.link.addFirst(newNode);
- this.map.set(key, newNode);
- }
- };
-
- // const lRUCache = new LRUCache(2);
- // lRUCache.put(1, 1); // 缓存是 {1=1}
- // lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
- // console.log(lRUCache.get(1)); // 返回 1
- // lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
- // console.log(lRUCache.get(2)); // 返回 -1 (未找到)
- // lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
- // console.log(lRUCache.get(1)); // 返回 -1 (未找到)
- // console.log(lRUCache.get(3)); // 返回 3
- // console.log(lRUCache.get(4)); // 返回 4
- class Node:
- def __init__(self, key, val):
- self.key = key
- self.val = val
- self.prev = None
- self.next = None
-
-
- class Link:
- def __init__(self):
- self.head = Node(-1, -1)
- self.tail = Node(-1, -1)
- self.head.next = self.tail
- self.tail.prev = self.head
-
- def removeNode(self, node):
- node.prev.next = node.next
- node.next.prev = node.prev
- node.prev = None
- node.next = None
-
- def addFirst(self, node):
- node.next = self.head.next
- self.head.next.prev = node
- self.head.next = node
- node.prev = self.head
-
-
- class LRUCache(object):
-
- def __init__(self, capacity):
- """
- :type capacity: int
- """
- self.capacity = capacity
- self.map = {}
- self.link = Link()
-
- def get(self, key):
- """
- :type key: int
- :rtype: int
- """
- if key in self.map:
- node = self.map[key]
- self.link.removeNode(node)
- self.link.addFirst(node)
- return node.val
- else:
- return -1
-
- def put(self, key, value):
- """
- :type key: int
- :type value: int
- :rtype: None
- """
- if key in self.map:
- node = self.map[key]
- self.link.removeNode(node)
- self.link.addFirst(node)
- node.val = value
- else:
- if len(self.map) == self.capacity:
- node = self.link.tail.prev
- self.link.removeNode(node)
- self.map.pop(node.key)
-
- node = Node(key, value)
- self.link.addFirst(node)
- self.map[key] = node
-
-
- # if __name__ == '__main__':
- # lRUCache = LRUCache(2)
- # lRUCache.put(1, 1) # 缓存是 {1=1}
- # lRUCache.put(2, 2) # 缓存是 {1=1, 2=2}
- # print(lRUCache.get(1)) # 返回1
- # lRUCache.put(3, 3) # 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
- # print(lRUCache.get(2)) # 返回-1
- # lRUCache.put(4, 4) # 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
- # print(lRUCache.get(1)) # 返回-1
- # print(lRUCache.get(3)) # 返回3
- # print(lRUCache.get(4)) # 返回4
- #include <stdio.h>
- #include <stdlib.h>
-
- #define MAX_SIZE 10000
-
- typedef struct NODE {
- int key;
- int val;
- struct NODE *prev;
- struct NODE *next;
- } Node;
-
- Node *new_Node(int key, int val) {
- Node *node = (Node *) malloc(sizeof(Node));
- node->key = key;
- node->val = val;
- node->prev = NULL;
- node->next = NULL;
- return node;
- }
-
- typedef struct LINK {
- Node *head;
- Node *tail;
- } Link;
-
- Link *new_Link() {
- Link *link = (Link *) malloc(sizeof(Link));
- link->head = new_Node(-1, -1);
- link->tail = new_Node(-1, -1);
- link->head->next = link->tail;
- link->tail->prev = link->head;
- return link;
- }
-
- void removeNode(Node *node) {
- node->prev->next = node->next;
- node->next->prev = node->prev;
- node->prev = NULL;
- node->next = NULL;
- }
-
- void addFirst(Link *link, Node *node) {
- node->next = link->head->next;
- link->head->next->prev = node;
- link->head->next = node;
- node->prev = link->head;
- }
-
-
- typedef struct {
- int capacity;
- Node *map[MAX_SIZE];
- int map_size;
- Link *link;
- } LRUCache;
-
-
- LRUCache *lRUCacheCreate(int capacity) {
- LRUCache *lru = (LRUCache *) malloc(sizeof(LRUCache));
- lru->capacity = capacity;
- lru->link = new_Link();
-
- lru->map_size = 0;
- for (int i = 0; i < MAX_SIZE; i++) {
- lru->map[i] = NULL;
- }
-
- return lru;
- }
-
- int lRUCacheGet(LRUCache *lru, int key) {
- if (lru->map[key] != NULL) {
- Node *node = lru->map[key];
- removeNode(node);
- addFirst(lru->link, node);
- return node->val;
- } else {
- return -1;
- }
- }
-
- void lRUCachePut(LRUCache *lru, int key, int value) {
- if (lru->map[key] != NULL) {
- Node *node = lru->map[key];
- removeNode(node);
- addFirst(lru->link, node);
- node->val = value;
- } else {
- if (lru->map_size == lru->capacity) {
- Node *removed = lru->link->tail->prev;
- removeNode(removed);
- lru->map[removed->key] = NULL;
- lru->map_size--;
- }
-
- Node *newNode = new_Node(key, value);
- addFirst(lru->link, newNode);
- lru->map[key] = newNode;
- lru->map_size++;
- }
- }
-
- void lRUCacheFree(LRUCache *lru) {
- Node *cur = lru->link->head;
-
- while (cur != NULL) {
- Node *next = cur->next;
- free(cur);
- cur = next;
- }
-
- free(lru);
- }
-
- //int main() {
- // LRUCache *lru = lRUCacheCreate(2);
- // lRUCachePut(lru, 1, 1);
- // lRUCachePut(lru, 2, 2);
- // printf("%d\n", lRUCacheGet(lru, 1));
- // lRUCachePut(lru, 3, 3);
- // printf("%d\n", lRUCacheGet(lru, 2));
- // lRUCachePut(lru, 4, 4);
- // printf("%d\n", lRUCacheGet(lru, 1));
- // printf("%d\n", lRUCacheGet(lru, 3));
- // printf("%d\n", lRUCacheGet(lru, 4));
- //
- // lRUCacheFree(lru);
- //
- // return 0;
- //}
- #include <bits/stdc++.h>
- using namespace std;
-
- class Node {
- public:
- int key{-1};
- int val{-1};
- Node *prev{};
- Node *next{};
-
- Node() = default;
-
- Node(int key, int val) : key(key), val(val) {}
- };
-
- class Link {
- public:
- Node *head;
- Node *tail;
-
- Link() {
- this->head = new Node();
- this->tail = new Node();
- this->head->next = this->tail;
- this->tail->prev = this->head;
- }
-
- static void removeNode(Node *node) {
- node->next->prev = node->prev;
- node->prev->next = node->next;
- node->prev = nullptr;
- node->next = nullptr;
- }
-
- void addFirst(Node *node) const {
- node->next = this->head->next;
- this->head->next->prev = node;
- this->head->next = node;
- node->prev = this->head;
- }
- };
-
- class LRUCache {
- public:
- int capacity;
- map<int, Node *> map;
- Link *link;
-
- explicit LRUCache(int capacity) {
- this->capacity = capacity;
- this->link = new Link();
- }
-
- int get(int key) {
- if (this->map.count(key) > 0) {
- Node *node = this->map[key];
- Link::removeNode(node);
- this->link->addFirst(node);
- return node->val;
- } else {
- return -1;
- }
- }
-
- void put(int key, int value) {
- if (this->map.count(key) > 0) {
- Node *node = this->map[key];
- Link::removeNode(node);
- this->link->addFirst(node);
- node->val = value;
- } else {
- if (this->map.size() == this->capacity) {
- Node *removed = this->link->tail->prev;
- Link::removeNode(removed);
- this->map.erase(this->map.find(removed->key));
- }
-
- Node *newNode = new Node(key, value);
- this->link->addFirst(newNode);
- this->map[key] = newNode;
- }
- }
- };
-
-
- //int main() {
- // LRUCache lru(2);
- // lru.put(1, 1);
- // lru.put(2, 2);
- // cout << lru.get(1) << endl;
- // lru.put(3, 3);
- // cout << lru.get(2) << endl;
- // lru.put(4, 4);
- // cout << lru.get(1) << endl;
- // cout << lru.get(3) << endl;
- // cout << lru.get(4) << endl;
- //
- // return 0;
- //}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。