思路:
1)使用什么数据结构?
有key和value要想到使用HashSet,但HashSet是无序的,所以访问或者维护结点的时间顺序要想到使用链表、栈、队列。本题在get存在的键时,要将保存该键的结点放到特殊位置(链表头部用于保存最新put或者get的结点),然后删除原先位置的结点,因此使用双向链表最合适(删除结点方便,不需要遍历)。综上,需要使用HashSet和双向链表。
2)如何使用数据结构完成本题?
HashSet的key和双向链表保存的key相同,HashSet的value保存的是相应key所对应的结点。双向链表结点的value保存的是真正的键值。进行get和put操作时,要处理HashSet和双向链表。
3)如何完成get和put操作?
1、定义addToHead()、removeNode()、moveToHead()、removeTail()函数
addToHead():put不存在的关键字
moveToHead():get或者put已存在的关键字,将该结点移动到链表头部(先调用removeNode(),再调用addToHead())
removeTail():应该在写入新数据之后,如果缓存容量达到上限,调用该函数删除最久未使用的结点,并返回被删除的结点(方便通过结点.key删除哈希表中对应的项)
2、get不改变哈希表,只改变双向链表。put会改变哈希表和双向链表,如果是put已存在的关键字,不用考虑缓存容量,否则put新关键字后,需判断是否超过缓存容量,如果超过需要删除最久未被使用的结点。
学习点:
1、在双向链表中,通过创建虚拟头结点和尾结点避免在增加和删除结点时考虑边界问题。
2、将最新被操作的结点放在链表头部,最久未被使用的结点放在链表尾部。通过使用头插法可以实现。
3、使用双向链表可以避免在删除结点时需要遍历链表