LRU算法Python實現


LRU 算法描述

LRU 算法實際上是讓你設計數據結構:首先要接收一個 capacity 參數作為緩存的最大容量,然后實現兩個 API,一個是 put(key, val) 方法存入鍵值對,另一個是 get(key) 方法獲取 key 對應的 val,如果 key 不存在則返回 -1。

注意哦,get 和 put 方法必須都是 O(1) 的時間復雜度,我們舉個具體例子來看看 LRU 算法怎么工作。

  

/* 緩存容量為 2 */
LRUCache cache = new LRUCache(2);
// 你可以把 cache 理解成一個隊列
// 假設左邊是隊頭,右邊是隊尾
// 最近使用的排在隊頭,久未使用的排在隊尾
// 圓括號表示鍵值對 (key, val)

cache.put(1, 1);
// cache = [(1, 1)]
cache.put(2, 2);
// cache = [(2, 2), (1, 1)]
cache.get(1);       // 返回 1
// cache = [(1, 1), (2, 2)]
// 解釋:因為最近訪問了鍵 1,所以提前至隊頭
// 返回鍵 1 對應的值 1
cache.put(3, 3);
// cache = [(3, 3), (1, 1)]
// 解釋:緩存容量已滿,需要刪除內容空出位置
// 優先刪除久未使用的數據,也就是隊尾的數據
// 然后把新的數據插入隊頭
cache.get(2);       // 返回 -1 (未找到)
// cache = [(3, 3), (1, 1)]
// 解釋:cache 中不存在鍵為 2 的數據
cache.put(1, 4);    
// cache = [(1, 4), (3, 3)]
// 解釋:鍵 1 已存在,把原始值 1 覆蓋為 4
// 不要忘了也要將鍵值對提前到隊頭

 

LRU 算法設計

分析上面的操作過程,要讓 put 和 get 方法的時間復雜度為 O(1),我們可以總結出 cache 這個數據結構必要的條件:查找快,插入快,刪除快,有順序之分。

因為顯然 cache 必須有順序之分,以區分最近使用的和久未使用的數據;而且我們要在 cache 中查找鍵是否已存在;如果容量滿了要刪除最后一個數據;每次訪問還要把數據插入到隊頭。

那么,什么數據結構同時符合上述條件呢?哈希表查找快,但是數據無固定順序;鏈表有順序之分,插入刪除快,但是查找慢。所以結合一下,形成一種新的數據結構:哈希鏈表。

LRU 緩存算法的核心數據結構就是哈希鏈表,雙向鏈表和哈希表的結合體。這個數據結構長這樣:

 

 需要刪除操作。刪除一個節點不光要得到該節點本身的指針,也需要操作其前驅節點的指針,而雙向鏈表才能支持直接查找前驅,保證操作的時間復雜度 O(1)。

'''
方法一
class LRUCache:
    #@param capacity,an integer
    def __init__(self,capacity):
        self.cache ={}
        self.used_list=[]
        self.capacity = capacity
    #@return an integer
    def get(self,key):
        if key in self.cache:
            #使用一個list來記錄訪問的順序,最先訪問的放在list的前面,最后訪問的放在list的后面,故cache已滿時,則刪除list[0],然后插入新項;
            if key != self.used_list[-1]:
                self.used_list.remove(key)
                self.used_list.append(key)
            return self.cache[key]
        else:
            return -1
    def put(self,key,value):
        if key in self.cache:
            self.used_list.remove(key)
        elif len(self.cache) == self.capacity:
            self.cache.pop(self.used_list.pop(0))
        self.used_list.append(key)
        self.cache[key] = value
'''
 
#方法二:
import collections
 
#基於orderedDict實現
class LRUCache(collections.OrderedDict):
    '''
    function:利用collection.OrdereDict數據類型實現最近最少使用的算法
    OrdereDict有個特殊的方法popitem(Last=False)時則實現隊列,彈出最先插入的元素
    而當Last=True則實現堆棧方法,彈出的是最近插入的那個元素。
    實現了兩個方法:get(key)取出鍵中對應的值,若沒有返回None
    set(key,value)更具LRU特性添加元素
    '''
    def __init__(self,size=5):
        self.size = size
        self.cache = collections.OrderedDict()#有序字典
 
    def get(self,key):
        if key in self.cache.keys():
            #因為在訪問的同時還要記錄訪問的次數(順序)
            value = self.cache.pop(key)
            #保證最近訪問的永遠在list的最后面
            self.cache[key] = value
            return value
        else:
            value = None
            return value
 
    def put(self,key,value):
        if key in self.cache.keys():
            self.cache.pop(key)
            self.cache[key] = value
        elif self.size == len(self.cache):
            self.cache.popitem(last=False)
            self.cache[key] = value
        else:
            self.cache[key] = value
 
if __name__ == '__main__':
    test = LRUCache()
    test.put('a',1)
    test.put('b',2)
    test.put('c',3)
    test.put('d',4)
    test.put('e',5)
    # test.put('f',6)
    print (test.get('a'))

 

  參考:https://blog.csdn.net/qq_35810838/article/details/83035759

                    https://labuladong.gitbook.io/algo/gao-pin-mian-shi-xi-lie/lru-suan-fa

 


免責聲明!

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



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