【题目】
设计一种缓存结构,该结构在构造时确定大小,假设大小为K,并有两个功能:
- set(key, value):将记录(key, value)插入该结构
- get(key):返回key对应的value值
【要求】
- set和get的时间复杂度为O(1)
- 某个key的set或get操作一旦发生,认为这个key的记录成了最经常使用的
- 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的
【基本思路】
这种缓存结构可以由双端队列与哈希表结合的方式实现。首先实现一个基本的双向链表节点结构,如下:
#python3.5
class Node:
def __init__(self, value):
self.value = value
self.pre = None
self.next = None
根据双向链表节点结构Node,实现一种双向链表结构DoubleLinkedList,在该结构中优先级最低的是头节点head,优先级最高的是尾节点Tail。这个结构有以下三种操作:
- addNode。加入一个节点,并将该节点设置成链表的尾部
- moveNodeToTail。对链表中的任意一个节点,可以分离出来并放到整个链表的尾部。
- removeHead。移除链表的头节点,并将head设置为head.next。
具体实现如下:
class DoubleLinkedList:
def __init__(self):
self.head = None
self.tail = None
def addNode(self, newNode):
if newNode == None:
return
if self.head == None:
self.head = newNode
self.tail = newNode
else:
self.tail.next = newNode
newNode.pre = self.tail
self.tail = newNode
def moveNodeToTail(self, node):
if node == None:
return
if node == self.tail:
return
if node == self.head:
self.head = node.next
self.head.pre = None
else:
node.pre.next = node.next
node.next.pre = node.pre
self.tail.next = node
node.next = None
node.pre = self.tail
self.tail = node
def removeHead(self):
if self.head == None:
return None
res = self.head
if self.head == self.tail:
self.head == None
self.tail == None
else:
self.head = res.next
self.head.pre = None
res.next = None
return res
最后实现最终的缓冲结构。如何把记录之间按照“访问经常度”来排序,就是上文提到的DoubleLinkedList结构。一旦有新的记录,直接放到链表的尾部。一旦获得(get)或设置(set)一个记录,就直接将该key对应的node调整到链表尾部。cache一旦满了,就删除链表的头节点所表示的记录。
为了得到key -> node以及node -> key的关系,使用两个哈希表来建立两者之间的映射关系。
【代码实现】
#python3.5
class Node:
def __init__(self, value):
self.value = value
self.pre = None
self.next = None
class DoubleLinkedList:
def __init__(self):
self.head = None
self.tail = None
def addNode(self, newNode):
if newNode == None:
return
if self.head == None:
self.head = newNode
self.tail = newNode
else:
self.tail.next = newNode
newNode.pre = self.tail
self.tail = newNode
def moveNodeToTail(self, node):
if node == None:
return
if node == self.tail:
return
if node == self.head:
self.head = node.next
self.head.pre = None
else:
node.pre.next = node.next
node.next.pre = node.pre
self.tail.next = node
node.next = None
node.pre = self.tail
self.tail = node
def removeHead(self):
if self.head == None:
return None
res = self.head
if self.head == self.tail:
self.head == None
self.tail == None
else:
self.head = res.next
self.head.pre = None
res.next = None
return res
class MyCache:
def __init__(self, capacity):
self.nodeKeyMap = {}
self.keyNodeMap = {}
self.capacity = capacity
self.nodeList = DoubleLinkedList()
def get(self, key):
if key in self.keyNodeMap:
res = self.keyNodeMap[key]
self.nodeList.moveNodeToTail(res)
return res.value
return None
def set(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.addNode(node)
if len(self.keyNodeMap) == self.capacity + 1:
self.removeMostUnusedCache()
def removeMostUnusedCache(self):
node = self.nodeList.removeHead()
key = self.nodeKeyMap[node]
del self.keyNodeMap[key]
del self.nodeKeyMap[node]