1. 程式人生 > 其它 >LRU快取機制-python

LRU快取機制-python

問題:

# 運用你所掌握的資料結構,設計和實現一個 LRU (最近最少使用) 快取機制 。 
#
#
#
# 實現 LRUCache 類:
#
#
# LRUCache(int capacity) 以正整數作為容量 capacity 初始化 LRU 快取
# int get(int key) 如果關鍵字 key 存在於快取中,則返回關鍵字的值,否則返回 -1 。
# void put(int key, int value) 如果關鍵字已經存在,則變更其資料值;如果關鍵字不存在,則插入該組「關鍵字-值」。當快取容量達到上
# 限時,它應該在寫入新資料之前刪除最久未使用的資料值,從而為新的資料值留出空間。
#

題解:

#### 方法一:雜湊表 + 雙向連結串列

**演算法**

LRU 快取機制可以通過雜湊表輔以雙向連結串列實現,我們用一個雜湊表和一個雙向連結串列維護所有在快取中的鍵值對。

- 雙向連結串列按照被使用的順序儲存了這些鍵值對,靠近頭部的鍵值對是最近使用的,而靠近尾部的鍵值對是最久未使用的。

- 雜湊表即為普通的雜湊對映(HashMap),通過快取資料的鍵對映到其在雙向連結串列中的位置。

這樣以來,我們首先使用雜湊表進行定位,找出快取項在雙向連結串列中的位置,隨後將其移動到雙向連結串列的頭部,即可在 *O(1)* 的時間內完成 `get` 或者 `put` 操作。具體的方法如下:

- 對於 `get` 操作,首先判斷 `key` 是否存在:

- 如果 `key` 不存在,則返回 *-1*;

- 如果 `key` 存在,則 `key` 對應的節點是最近被使用的節點。通過雜湊表定位到該節點在雙向連結串列中的位置,並將其移動到雙向連結串列的頭部,最後返回該節點的值。

- 對於 `put` 操作,首先判斷 `key` 是否存在:

- 如果 `key` 不存在,使用 `key` 和 `value` 建立一個新的節點,在雙向連結串列的頭部新增該節點,並將 `key` 和該節點新增進雜湊表中。然後判斷雙向連結串列的節點數是否超出容量,如果超出容量,則刪除雙向連結串列的尾部節點,並刪除雜湊表中對應的項;

- 如果 `key` 存在,則與 `get` 操作類似,先通過雜湊表定位,再將對應的節點的值更新為 `value`,並將該節點移到雙向連結串列的頭部。

上述各項操作中,訪問雜湊表的時間複雜度為 *O(1)*,在雙向連結串列的頭部新增節點、在雙向連結串列的尾部刪除節點的複雜度也為 *O(1)*。而將一個節點移到雙向連結串列的頭部,可以分成「刪除該節點」和「在雙向連結串列的頭部新增節點」兩步操作,都可以在 *O(1)* 時間內完成。

參考程式碼:
# leetcode submit region begin(Prohibit modification and deletion)
class DLinkedNode:
    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None

class LRUCache:

    def __init__(self, capacity: int):
        self.cache 
= {} self.head = DLinkedNode() self.tail = DLinkedNode() self.head.next = self.tail self.tail.prev = self.head self.capacity = capacity self.size = 0 def get(self, key: int) -> int: if key not in self.cache: return -1 node = self.cache[key] self.moveToHead(node) return node.value def put(self, key: int, value: int) -> None: if key not in self.cache: node = DLinkedNode(key, value) self.cache[key ] = node self.addToHead(node) self.size += 1 if self.size > self.capacity: removed = self.removeTail() self.cache.pop(removed.key) # 刪除hash表中的對應項 self.size -= 1 else: node = self.cache[key] node.value = value self.moveToHead(node) def addToHead(self, node): node.prev = self.head node.next = self.head.next self.head.next.prev = node self.head.next = node def removeNode(self, node): node.prev.next = node.next node.next.prev = node.prev def moveToHead(self, node): self.removeNode(node) self.addToHead(node) def removeTail(self): node = self.tail.prev self.removeNode(node) return node
時刻記著自己要成為什麼樣的人!