亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python實(shí)現(xiàn)LRU算法的2種方法

系統(tǒng) 2022 0

LRU:least recently used,最近最少使用算法。它的使用場景是:在有限的空間中存儲對象時(shí),當(dāng)空間滿時(shí),會按一定的原則刪除原有的對象,常用的原則(算法)有LRU,F(xiàn)IFO,LFU等。在計(jì)算機(jī)的Cache硬件,以及主存到虛擬內(nèi)存的頁面置換,還有Redis緩存系統(tǒng)中都用到了該算法。我在一次面試和一個(gè)筆試時(shí),也遇到過這個(gè)問題。

LRU的算法是比較簡單的,當(dāng)對key進(jìn)行訪問時(shí)(一般有查詢,更新,增加,在get()和set()兩個(gè)方法中實(shí)現(xiàn)即可)時(shí),將該key放到隊(duì)列的最前端(或最后端)就行了,這樣就實(shí)現(xiàn)了對key按其最后一次訪問的時(shí)間降序(或升序)排列,當(dāng)向空間中增加新對象時(shí),如果空間滿了,刪除隊(duì)尾(或隊(duì)首)的對象。

在Python中,可以使用collections.OrderedDict很方便的實(shí)現(xiàn)LRU算法,當(dāng)然,如果你想不到用OrderedDict,那可以用dict+list來實(shí)現(xiàn)。本文主要參考了LRU CACHE IN PYTHON,寫的非常好,既實(shí)現(xiàn)了功能,又簡潔易讀。方法一的代碼與參考文章基本相同,方法二是我自己想出來的,比較繁瑣一些,其實(shí)OrderedDict本身也是類似的這種機(jī)制來實(shí)現(xiàn)的有序。

不過,下面的實(shí)現(xiàn)是有問題的,這個(gè)cache的key:value鍵值對中,value只能是不可變類型。因?yàn)椋绻鹶alue是可變類型,那對于同一個(gè)key,所有調(diào)用get(key)方法返回的value都是指向同一個(gè)可變對象的,當(dāng)修改其中一個(gè)value時(shí),那所有的value都會被修改了,即使你沒有調(diào)用set()方法也會這樣。這是我們不希望看到的。解決方法我想到了兩種,一是可變對象序列化后再存儲,即將可變對象轉(zhuǎn)為不可變對象;二是仍存儲可變對象,但get()時(shí),返回一個(gè)深拷貝,這樣每個(gè)get()調(diào)用返回的對象就不會相互影響了。推薦第一種方法。另外,對于key,推薦使用str/unicode類型。

當(dāng)并發(fā)時(shí),還會存在一個(gè)問題,因?yàn)檫@涉及到對公共資源的寫操作,所以必須要對set()加鎖。其實(shí),在并發(fā)情況下,所有對公共資源的寫操作都要加鎖。如果不存在并發(fā)的情況,只有單線程,那可以不加鎖。

方法一:用OrderedDict實(shí)現(xiàn)(推薦)

復(fù)制代碼 代碼如下:

from collections import OrderedDict
?
?
class LRUCache(OrderedDict):
??? '''不能存儲可變類型對象,不能并發(fā)訪問set()'''

??? def __init__(self,capacity):
??????? self.capacity = capacity
??????? self.cache = OrderedDict()
????

??? def get(self,key):
??????? if self.cache.has_key(key):
??????????? value = self.cache.pop(key)
??????????? self.cache[key] = value
??????? else:
??????????? value = None
????????
??????? return value
????

??? def set(self,key,value):
??????? if self.cache.has_key(key):
??????????? value = self.cache.pop(key)
??????????? self.cache[key] = value
??????? else:
??????????? if len(self.cache) == self.capacity:
??????????????? self.cache.popitem(last = False)??? #pop出第一個(gè)item
??????????????? self.cache[key] = value
??????????? else:
??????????????? self.cache[key] = value


測試代碼如下
復(fù)制代碼 代碼如下:

c = LRUCache(5)
?
for i in range(5,10):
??? c.set(i,10*i)
?
?
print c.cache, c.cache.keys()
?
c.get(5)
c.get(7)
?
print c.cache, c.cache.keys()
?
c.set(10,100)
print c.cache, c.cache.keys()
?
c.set(9,44)
print c.cache, c.cache.keys()

輸出如下

復(fù)制代碼 代碼如下:

OrderedDict([(5, 50), (6, 60), (7, 70), (8, 80), (9, 90)])???? [5, 6, 7, 8, 9]
OrderedDict([(6, 60), (8, 80), (9, 90), (5, 50), (7, 70)])???? [6, 8, 9, 5, 7]
OrderedDict([(8, 80), (9, 90), (5, 50), (7, 70), (10, 100)])?? [8, 9, 5, 7, 10]
OrderedDict([(8, 80), (5, 50), (7, 70), (10, 100), (9, 90)])?? [8, 5, 7, 10, 9]


方法二:用dict+list實(shí)現(xiàn)(不推薦)

復(fù)制代碼 代碼如下:

class LRUCache(object):
??? '''不能存儲可變類型對象,不能并發(fā)訪問set()'''
?
??? def __init__(self,capacity):
??????? self.l = []
??????? self.d = {}
??????? self.capacity = capacity
?????????

??? def get(self,key):
??????? if self.d.has_key(key):
??????????? value = self.d[key]
??????????? self.l.remove(key)
??????????? self.l.insert(0,key)
??????? else:
??????????? value = None
?????????
??????? return value
?????

??? def set(self,key,value):
??????? if self.d.has_key(key):
??????????? self.l.remove(key)
??????? elif len(self.d) == self.capacity:
??????????????? oldest_key = self.l.pop()
??????????????? self.d.pop(oldest_key)
?????????????????
??????? self.d[key] = value
??????? self.l.insert(0, key)


測試代碼如下
復(fù)制代碼 代碼如下:

c = LRUCache(5)
?
for i in range(5,10):
??? c.set(i,10*i)
?
?
print c.d,c.l
?
c.get(5)
c.get(7)
?
print c.d,c.l
?
c.set(10,100)
print c.d,c.l
?
c.set(9,44)
print c.d,c.l

輸出為

復(fù)制代碼 代碼如下:

{8: 80, 9: 90, 5: 50, 6: 60, 7: 70}?? [9, 8, 7, 6, 5]
{8: 80, 9: 90, 5: 50, 6: 60, 7: 70}?? [7, 5, 9, 8, 6]
{5: 50, 7: 70, 8: 80, 9: 90, 10: 100} [10, 7, 5, 9, 8]
{5: 50, 7: 70, 8: 80, 9: 44, 10: 100} [9, 10, 7, 5, 8]


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 午夜色网站 | 最近中文字幕无免费视频 | 国产v欧美v日韩在线观看 | 亚洲在线视频观看 | 色综合久久综合欧美综合 | 福利免费在线 | 97久久国产一区二区三区四区 | 久久久久琪琪免费影院 | 九色国产 | 欧美日本一本 | 欧美一级高清毛片aaa | 国产成人综合自拍 | 欧美成人a | 一区二区美女视频 | 天天干在线观看 | 国产香蕉免费精品视频 | 亚洲综合在线视频 | 99精品全国免费7观看视频 | 国产成人a v在线影院 | 日本伊人精品一区二区三区 | 97影院理论 | 日产精品久久久一区二区 | 久久日韩精品 | 激情综合网五月激情 | 99热这里都是精品 | 久久综合偷偷噜噜噜色 | 成年男女免费视频观看性 | 中文字幕日本不卡一二三区 | 欧美激情精品久久久久 | 久久福利资源网站免费看 | 国产一区二区福利久久 | 国产精品亚洲一区二区麻豆 | 91福利社在线观看 | 擼擼色在线看观看免费 | 久久亚洲国产精品五月天婷 | 国产欧美一区二区三区在线 | 日本伊人精品一区二区三区 | 4hu四虎 | 四虎影音先锋 | 97精品久久天干天天蜜 | 国产免费一级片 |