【題目】 設計一種快取結構,該結構在構造時確定大小,假設大小為k,並有兩個功能:
get(key):返回key對應的value值;
set(key,value):將**記錄(key,value)**插入該結構。
【要求】
get和set方法的時間複雜度為o(1
)o(1)
o(1)
。
某個key的get和set操作一旦發生,認為這個key的記錄成了最經常使用的。
當快取的大小超過k時,移除最不經常使用的記錄,即get和set最久遠的。
【舉例】 假設快取結構的例項是cache,大小為3,並依次發生如下行為:
cache.set(「a」,1)。最經常使用的記錄為(「a」,1)。
cache.set(「b」,2)。最經常使用的記錄為(「b」,2),(「a」,1)變為最不經常的。
cache.set(「c」,3)。最經常使用的記錄為(「c」,2),(「a」,1)還是最不經常的。
cache.get(「a」)。最經常使用的記錄為(「a」,1),(「b」,2)變為最不經常的。
cache.set(「d」,4)。大小超過了3,所以移除此時最不經常使用的記錄 (「b」,2),加入記錄(「d」,4)。
此時(「d」,4)為最經常使用的記錄,然後(「c」,2)變為最不經常使用的記錄。
lru(least recently used):最近最少使用演算法。
雜湊表本身get和set方法的時間複雜度為o(1
)o(1)
o(1)
,但需要在k容量下維護最近最經常使用的記錄,因此在其基礎上,再增添結構。
注意:快取結構需要更新內部節點(值)位置,因此不可以用collections
模組中deque
實現。
# value儲存在node中
class
node
:def
__init__
(self, value)
: self.value = value
self.last =
none
self.
next
=none
# 雙端佇列
# 注意:快取結構需要更新內部節點位置,因此不可以用collections模組中deque實現
class
nodedoublelinkedlist
:def
__init__
(self)
: self.head =
none
self.tail =
none
# 新增節點至末尾
defaddtail
(self, node)
:if self.tail is
none
: self.head = node
self.tail = node
else
: self.tail.
next
= node
node.last = self.tail
self.tail = node
# 移除頭節點
defremovehead
(self)
:if self.head is
none
:return
res = self.head
if self.head is self.tail:
self.head =
none
self.tail =
none
else
: self.head = res.
next
res.
next
=none
self.head.last =
none
return res
# 將已存在的節點移至末尾
defmovenodetotail
(self, node)
:if node == self.tail:
return
# 至少有兩個節點,處理前後節點鏈結
if node == self.head:
self.head = self.head.
next
self.head.last =
none
else
: node.last.
next
= node.
next
node.
next
.last = node.last
# 移至末尾,並標記為tail
node.last = self.tail
self.tail.
next
= node
self.tail = node
class
mycache
:def
__init__
(self, capacity)
: self.keynodemap =
self.nodekeymap =
self.nodelist = nodedoublelinkedlist(
) self.capacity = capacity
defget(self, key)
:if key not
in self.keynodemap:
return
none
node = self.keynodemap.get(key)
self.nodelist.movenodetotail(node)
return node
# 存在則更新,不存在則新增
defset
(self, key, value)
:if key in self.keynodemap:
node = self.keynodemap[key]
node.value = value
self.nodelist.movenodetotail(node)
else
: node = node(value)
self.keynodemap[key]
= node
self.nodekeymap[node]
= key
self.nodelist.addtail(node)
# 超出容量,移除最不經常使用的節點
iflen
(self.nodekeymap)
== self.capacity +1:
head = self.nodelist.removehead(
) key = self.nodekeymap[head]
del self.keynodemap[key]
del self.nodekeymap[node]
# 簡單測試
if __name__ ==
'__main__'
: cache = mycache(3)
cache.
set(
'a',1)
cache.
set(
'b',2)
cache.
set(
'c',3)
cache.
set(
'd',4)
nodelist = cache.nodelist
cur = nodelist.head
while cur !=
none
:print
(cur.value, end=
' ')
cur = cur.
next
大容量U盤顯示為小容量的解決方法
今天在電腦上開啟好久沒用的u盤一看,發現其容量為5.4g。同時檢視u盤標籤發現是16g的容量,然後就是格式化操作,結果發現沒有任何效果。通過搜尋發現在windows上可以通過如下方式解決 1 win r 開啟cmd 2 diskpart 會又彈出乙個cmd視窗 3 list disk 檢視當前電腦上...
HashMap 容量為2次冪的原因
我們都知道 hashmap 的底層是乙個陣列加鍊表的結構,當向其中新增乙個元素的時候,需要根據key的hash值,去確定其在陣列中的具體位置。看原始碼,我們可以發現,確定陣列位置的實現是i n 1 hash,其中 n 代表陣列的長度,即map的容量。當n為2的冪次方時,n 1 hash 的值是均勻分...
HashMap的初始容量設定為多少合適?
我們知道對於list map這種底層是基於陣列的動態容器,在擴容時會進行陣列複製,因此為了避免這種額外開銷,應該盡量在建立時指定大小。對於沒有負載因子的如list,其擴容策略為滿了後下次插入進行擴容,因此初始化大小為需要大小即可 對於存在負載因子的hashmap hashset等,其擴容策略為本次插...