1. 链表(上):如何实现LRU缓存淘汰算法?
1.1. 常见的缓存策略
- 先进先出策略 FIFO(First In,First Out)
- 最少使用策略 LFU(Least Frequently Used)
- 最近最少使用策略 LRU(Least Recently Used)
1.2. 常用的链表结构
-
单链表
-
循环链表
- 约瑟夫问题
-
双向链表
1.3. 链表和数组性能对比
- 数组:插入删除时间复杂度O(n), 随机访问时间复杂度O(1)
- 链表:插入删除时间复杂度O(1), 随机访问时间复杂度O(n)
2. 链表(下):如何轻松写出正确的链表代码?
2.1. 写好链表的几种技巧
- 理解指针和引用的含义
- 警惕指针丢失和内存泄漏
- 利用哨兵简化实现难度
- 重点留意边界条件处理
- 举例画图,辅助思考
- 多写多练,没有捷径
2.2. 五个常见的链表操作
- 单链表反转
- 链表中环的检测
- 两个有序链表合并
- 删除链表倒数第n个节点
- 求链表的中间节点
3. 案例
- java
import java.util.HashMap;
import java.util.Map;
/**
* 基于数组实现LRU缓存
* 1. 空间复杂度为O(n)
* 2. 时间复杂度为O(n)
* 3. 不支持null的缓存
*/
public class LRUBasedArray<T> {
// 把1左移了3位 1 x 2^3
private static final int DEFAULT_CAPACITY = (1 << 3);
// 数组大小
private int size;
// 数组内容
private T[] value;
// 缓存集合
private Map<T, Integer> holder;
public LRUBasedArray() {
this(DEFAULT_CAPACITY);
}
public LRUBasedArray(int capacity) {
this.value = (T[]) new Object[capacity];
this.size = 0;
this.holder = new HashMap<T, Integer>(capacity);
}
/**
* 模拟访问某个值
* @param object
*/
public void offer(T object) {
if(object == null) {
throw new IllegalArgumentException("该缓存容器不支持null!");
}
Integer index = holder.get(object);
if(index == null) {
if (isFull()) {
removeAndCache(object);
}else {
cache(object, size);
}
} else {
update(index);
}
}
/**
* 缓存满的情况,踢出最后一个元素后,再缓存到数组的头部
* @param object
*/
public void removeAndCache(T object) {
T key = value[--size];
holder.remove(key);
cache(object, size);
}
/**
* 若缓存中有指定的值,则更新位置
* @param end
*/
public void update(int end) {
T target = value[end];
rightShift(end);
value[0] = target;
holder.put(target, 0);
}
/**
* 缓存数据到头部,但要先右移
* @param object
* @param end
*/
public void cache(T object, int end) {
rightShift(end);
value[0] = object;
holder.put(object, 0);
size ++;
}
/**
* end左边的数据统一右移一位
* @param end
*/
private void rightShift(int end) {
for (int i = end -1; i >= 0; i--) {
value[i + 1] = value[i];
holder.put(value[i], i + 1);
}
}
public boolean isContain(T object) {
return holder.containsKey(object);
}
public boolean isEmpty() {
return size == 0;
}
public boolean isFull() {
return size == value.length;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for(int i = 0;i < size; i ++) {
sb.append(value[i]).append(" ");
}
return sb.toString();
}
public static void main(String[] args) {
// testWithException();
// testDefaultConstructor();
testSpecifiedConstructor(4);
}
private static void testWithException() {
LRUBasedArray<Integer>lru = new LRUBasedArray<>();
lru.offer(null);
}
public static void testDefaultConstructor() {
System.out.println("======无参测试========");
LRUBasedArray<Integer> lru = new LRUBasedArray<Integer>();
lru.offer(1);
lru.offer(2);
lru.offer(3);
lru.offer(4);
lru.offer(2);
System.out.println(lru);
lru.offer(6);
lru.offer(7);
lru.offer(8);
lru.offer(9);
System.out.println(lru);
}
public static void testSpecifiedConstructor(int capacity) {
System.out.println("======有参测试========");
LRUBasedArray<Integer> lru = new LRUBasedArray<Integer>(capacity);
lru.offer(1);
System.out.println(lru);
lru.offer(2);
System.out.println(lru);
lru.offer(3);
System.out.println(lru);
lru.offer(4);
System.out.println(lru);
lru.offer(2);
System.out.println(lru);
lru.offer(4);
System.out.println(lru);
lru.offer(7);
System.out.println(lru);
lru.offer(1);
System.out.println(lru);
lru.offer(2);
System.out.println(lru);
}
}
import java.util.Scanner;
/**
* 基于单链表的LRU算法
* @param <T>
*/
public class LRUBaseLinkedList<T> {
// 默认链表容量
private static final Integer DEFAULT_CAPACITY = (1 << 3);
// 头结点
private SNode<T> headNode;
// 链表长度
private Integer length;
// 链表容量
private Integer capacity;
public LRUBaseLinkedList() {
this(DEFAULT_CAPACITY);
}
public LRUBaseLinkedList(Integer capacity) {
this.headNode = new SNode<>();
this.capacity = capacity;
this.length = 0;
}
public void add(T data) {
SNode preNode = findPreNode(data);
// 链表中存在, 删除原数据, 再插入到链表的头部
if (preNode != null) {
deleteElemOptim(preNode);
insertElemAtBegin(data);
}else {
if (length >= this.capacity) {
// 删除尾结点
deleteElemAtEnd();
}
insertElemAtBegin(data);
}
}
/**
* 删除尾结点
*/
private void deleteElemAtEnd() {
SNode ptr = headNode;
// 空链表直接返回
if (ptr.getNext() == null) return;
// 倒数第二个结点
while(ptr.getNext().getNext() != null) {
ptr = ptr.getNext();
}
SNode tmp = ptr.getNext();
ptr.setNext(null);
tmp = null;
length --;
}
private void printAll() {
SNode node = headNode.getNext();
while(node != null) {
System.out.print(node.getElement() + " ");
node = node.getNext();
}
System.out.println();
}
/**
* 删除preNode结点下一个元素
* @param preNode
*/
private void deleteElemOptim(SNode preNode) {
SNode temp = preNode.getNext();
preNode.setNext(temp.getNext());
temp = null;
length --;
}
/**
* 链表头部插入结点
* @param data
*/
private void insertElemAtBegin(T data) {
SNode next = headNode.getNext();
headNode.setNext(new SNode(data, next));
length ++;
}
/**
* 获取查找到元素的前一个结点
* @param data
* @return
*/
public SNode findPreNode(T data) {
SNode node = headNode;
while(node.getNext() != null) {
if (data.equals(node.getNext().getElement())) {
return node;
}
node = node.getNext();
}
return null;
}
public class SNode<T> {
private T element;
private SNode next;
public SNode(T element) {
this.element = element;
}
public SNode(T element, SNode next) {
this.element = element;
this.next = next;
}
public SNode() {
this.next = null;
}
public T getElement() {
return element;
}
public void setElement(T element) {
this.element = element;
}
public SNode getNext() {
return next;
}
public void setNext(SNode next) {
this.next = next;
}
}
public static void main(String[] args) {
LRUBaseLinkedList list = new LRUBaseLinkedList();
Scanner sc = new Scanner(System.in);
while(true) {
list.add(sc.nextInt());
list.printAll();
}
}
}
/**
* 1. 单链表的插入、删除、查找操作
* 2. 链表中存储的都是int类型数据
* 3. 判断回文
*/
public class SinglyLinkedList {
private Node head = null;
public Node findByValue(int value) {
Node p = head;
while(p != null && p.data != value) {
p = p.next;
}
return p;
}
public Node findByIndex(int index) {
Node p = head;
int pos = 0;
while(p != null && pos != index) {
p = p.next;
++pos;
}
return p;
}
/**
* 无头结点
* 表头部插入
* 这种操作将与输入的顺序相反, 逆序
*/
public void insertToHead(int value) {
Node newNode = new Node(value, null);
insertToHead(newNode);
}
public void insertToHead(Node newNode) {
if (head == null) {
head = newNode;
} else {
newNode.next = head;
head = newNode;
}
}
public void insertTail(int value) {
Node newNode = new Node(value, null);
// 空链表, 可以插入新节点作为head, 也可以不操作
if (head == null) {
head = newNode;
} else {
Node q = head;
while(q.next != null) {
q = q.next;
}
q.next = newNode;
}
}
public void insertAfter(Node p, int value) {
Node newNode = new Node(value, null);
insertAfter(p, newNode);
}
public void insertAfter(Node p, Node newNode) {
if (p == null) return;
newNode.next = p.next;
p.next = newNode;
}
public void insertBefore(Node p, Node newNode) {
if (p == null) return;
if (head == p) {
insertToHead(newNode);
return;
}
Node q = head;
while(q != null && q.next != p) {
q = q.next;
}
if (q == null) return;
newNode.next = p;
q.next = newNode;
}
public void insertBefore(Node p, int value) {
Node newNode = new Node(value, null);
insertBefore(p,newNode);
}
public void deleteByNode(Node p) {
if(p == null || head == null) return;
if (p == head) {
head = head.next;
return;
}
Node q = head;
while(q != null && q.next != p) {
q = q.next;
}
if (q == null) return;
q.next = q.next.next;
}
/**
* 删除第一个值相等的结点
* @param value
*/
public void deleteByValue(int value) {
if (head == null) return;
Node p = head;
Node q = null;
while(p != null && p.data != value) {
q = p;
p = p.next;
}
if (p == null) return;
if (q == null) {
head = head.next;
} else {
q.next = q.next.next;
}
}
public void printAll() {
Node p = head;
while(p != null) {
System.out.print(p.data + " ");
p = p.next;
}
System.out.println();
}
public static Node createNode(int value) {
return new Node(value, null);
}
// 判断true或者false
public boolean IFResult(Node left, Node right) {
Node l = left;
Node r = right;
System.out.println("left_:"+l.data);
System.out.println("right_:"+r.data);
while (l != null && r != null) {
if (l.data == r.data) {
l = l.next;
r = r.next;
continue;
}else {
break;
}
}
if (l == null && r == null) {
return true;
} else {
return false;
}
}
public boolean palindrome() {
if (head == null) {
return false;
} else {
System.out.println("开始执行找到中间节点");
Node p = head;
Node q = head;
// 只有一个结点
if (p.next == null) {
return true;
}
while(q.next != null && q.next.next != null) {
p = p.next;
q = q.next.next;
}
System.out.println("中间节点" + p.data);
System.out.println("开始执行奇数节点的回文判断");
Node leftLink = null;
Node rightLink = null;
if(q.next == null) {
// p 一定为整个链表的中点,且节点数目为奇数
rightLink = p.next;
leftLink = inverseLinkList(p).next;
System.out.println("左边第一个节点"+leftLink.data);
System.out.println("右边第一个节点"+rightLink.data);
} else {
//p q 均为中点
rightLink = p.next;
leftLink = inverseLinkList(p);
}
return IFResult(leftLink, rightLink);
}
}
// 无头结点的链表翻转
public Node inverseLinkList(Node p) {
Node pre = null;
Node r = head;
System.out.println("z---" + r.data);
Node next = null;
while (r != p) {
next = r.next;
r.next = pre;
pre = r;
r = next;
}
r.next = pre;
return r;
}
// 带头结点的链表翻转
public Node inverseLinkList_head(Node p) {
// head 为新建的一个头结点
Node head = new Node(9999, null);
// p 为原来整个链表的头结点,现在head指向 整个链表
head.next = p;
// 带头结点的链表翻转等价于从第二个元素开始重新头插法建立链表
Node cur = p.next;
p.next = null;
Node next = null;
while (cur != null) {
next = cur.next;
cur.next = head.next;
head.next = cur;
System.out.println("first " + head.data);
cur = next;
}
// 返回左半部分的重点之前的那个结点,从此处开始同步像两边比较
return head;
}
public static class Node {
private int data;
private Node next;
public Node() {
}
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
public int getData() {
return data;
}
}
public boolean isLoop(Node head) {
if(head == null) return false;
Node slow = head;
Node fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
}
public static void main(String[] args) {
SinglyLinkedList link = new SinglyLinkedList();
int data[] = {1,2,5,3,1};
for (int i =0; i < data.length; i++) {
link.insertTail(data[i]);
}
link.printAll();
if (link.palindrome()){
System.out.println("回文");
}else{
System.out.println("不是回文");
}
}
}
- Scala
import scala.util.control.Breaks._
class Node(var data: Int, var next: Option[Node])
class SinglyLinkedListScala(var headOpt: Option[Node]) {
def this() = this(None)
def findByValue(value: Int): Option[Node] = {
headOpt.flatMap(head => {
var node = head
while (!node.data.equals(value) && node.next.isDefined) {
node = node.next.get
}
if (node.data.equals(value)) {
return Some(node)
} else {
return None
}
})
}
def insertToHead(value: Int): Unit = {
val newNode = new Node(value, None)
insertToHead(newNode)
}
def insertToHead(newNode: Node): Unit = {
headOpt match {
case None =>
// it's an empty linked list, make new node as head
headOpt = Some(newNode)
case Some(head) =>
newNode.next = Some(head)
headOpt = Some(newNode)
}
}
def insertTail(value: Int): Unit = {
val newNode = new Node(value, None)
insertTail(newNode)
}
def insertTail(newNode: Node): Unit = {
headOpt match {
case None =>
// it's an empty linked list, make new node as head
headOpt = Some(newNode)
case Some(head) =>
// need to start fo find from head to current tail
var node = head;
while(node.next.isDefined) {
node = node.next.get
}
// now node is the tail as node.next is None, add new tail
node.next = Some(newNode)
}
}
def deleteByNode(node: Node): Unit = {
headOpt.map(head => {
if (head.equals(node)) {
headOpt = node.next
} else {
var p: Node = head;
while(p.next.isDefined && !p.next.get.equals(node)) {
p = p.next.get
}
if(p.next.isEmpty) {
throw new IllegalArgumentException("could not find given node.")
}
p.next = node.next
}
})
}
def mkString(): String = {
headOpt.map(head => {
var node = head
val result = new StringBuilder
while(node.next.isDefined) {
result.append(node.data)
node = node.next.get
}
result.append(node.data)
result.mkString
}).getOrElse("")
}
// 回文判断
def isPalindrome(): Boolean = {
headOpt match {
case None => false
case Some(head) =>
var p: Node = head
var q: Node = head
if (p.next.isEmpty) {
return true
}
while(q.next.isDefined && q.next.get.next.isDefined) {
p = p.next.get
q = q.next.get.next.get
}
var leftLink: Option[Node] = None
var rightLink: Option[Node] = None
q.next match {
case None =>
rightLink = p.next
leftLink = inverseLink(p).next
case Some(_) =>
rightLink = p.next
leftLink = Some(inverseLink(p))
}
compareLinkedNodes(leftLink, rightLink)
}
}
def compareLinkedNodes(leftLink: Option[Node], rightLink:Option[Node]): Boolean = {
var left = leftLink
var right = rightLink
breakable {
while(left.isDefined && right.isDefined) {
if(!left.get.data.equals(right.get.data)) {
break
}
left = left.get.next
right = right.get.next
}
}
left.isEmpty && right.isEmpty
}
// 翻转链表
def inverseLink(node: Node): Node = {
if(headOpt.isEmpty) {
throw new IllegalArgumentException("list is empty.")
}
var pre: Option[Node] = None
var next: Option[Node] = None
var current: Option[Node] = headOpt
while (current.isDefined && !current.get.equals(node)) {
next = current.get.next
current.get.next = pre
pre = current
current = next
}
current.get.next = pre
current.get
}
}
object SinglyLinkedListScala {
def main(args: Array[String]): Unit = {
val lst = new SinglyLinkedListScala()
lst.insertTail(1)
lst.insertTail(2)
lst.insertTail(3)
lst.insertTail(1)
val result = lst.mkString()
print(result)
print(lst.isPalindrome())
}
}
- python
# 1.单链表的插入、删除、查找操作;
# 2.链表中存储的数据类型是Int
#
# Author: fan
class Node:
"""链表结构的Node结点"""
def __init__(self, data, next_node=None):
"""Node结点的初始化方法
参数:
data:存储的数据
next_node:下一个Node结点的引用地址
"""
self.__data = data
self.__next = next_node
@property
def data(self):
"""Node结点存储数据的获取
返回:
当前Node结点存储的数据
"""
return self.__data
@data.setter
def data(self, data):
"""Node结点存储数据的设置方法
参数:
data:新的存储数据
"""
self.__data = data
@property
def next_node(self):
"""获取Node结点的next指针值
返回:
next指针数据
"""
return self.__next
@next_node.setter
def next_node(self, next_node):
"""Node结点next指针的修改方法
参数:
next:新的下一个Node结点的引用
"""
self.__next = next_node
class SinglyLinkedList1:
"""单向链表"""
@property
def head(self):
return self.__head
@head.setter
def head(self, head):
self.__head = head
def __init__(self):
"""单向链表初始化方法"""
self.__head = None
self.__len = 0
def find_by_value(self, value):
"""按照数据值在单向列表中查找
参数:
value:查找的数据
返回:
Node
"""
cur = self.__head
while cur is not None and cur.data != value:
cur = cur.next_node
return cur
def find_by_index(self, index):
"""按照索引值在链表中查找
参数:
index:索引值
返回:
Node
"""
cur = self.__head
pos = 0
while cur is not None and pos != index:
cur = cur.next_node
pos += 1
return cur
def insert_to_head(self, value):
"""在链表的头部插入一个存储value数值的Node结点
参数:
value:将要存储的数据
"""
cur = Node(value)
cur.next_node = self.__head
self.__head = cur
self.__len += 1
def insert_after(self, node, value):
"""在链表的某个指定Node结点之后插入一个存储value数据的Node结点
参数:
node:指定的一个node结点
value:将要存储在新Node结点中的数据
"""
if node is None:
print("current node is invalid.")
return
new_node = Node(value)
new_node.next_node = node.next_node
node.next_node = new_node
self.__len += 1
def insert_before(self, node, value):
"""在链表的某个指定Node结点之前插入一个存储value数据的Node结点
参数:
node:指定的一个node结点
value:将要存储在新Node结点中的数据
"""
if node is None or self.__head is None:
print("node is None.")
return
if node == self.__head:
self.insert_to_head(value)
return
new_node = Node(value)
pre = self.__head
not_found = False
while pre.next_node != node:
if pre.next_node is None:
not_found = True
break
else:
pre = pre.next_node
if not not_found:
pre.next_node = new_node
new_node.next_node = node
self.__len += 1
def delete_by_node(self, node):
"""在链表中删除指定的Node结点
参数:
node:指定的Node结点
"""
if self.__head is None:
return
if node == self.__head:
self.__head = node.next_node
self.__len -= 1
return
pre = self.__head
not_found = False # 如果在整个链表当中都没有找到相应的结点,则标记为True
while pre.next_node != node:
if pre.next_node is None:
not_found = True
break
else:
pre = pre.next_node
if not not_found:
pre.next_node = node.next_node
self.__len -= 1
def delete_by_value(self, value):
"""在链表中删除指定存储数据的Node结点
参数:
value:指定的存储数据
"""
if self.__head is None:
return
if self.__head.data == value:
self.__head = self.__head.next_node
self.__len -= 1
pre = self.__head
node = self.__head.next_node
not_found = False
while node.data != value:
if node.next_node is None:
not_found = True
break
else:
pre = node
node = node.next_node
if not not_found:
pre.next_node = node.next_node
self.__len -= 1
def delete_last_n_node(self, n):
"""删除链表中倒数第N个结点(0 < n <= self.__len)
思路:
设置快、慢两个指针、快指针,快指针先行,慢指针不动;当快指针跨了N步以后,快、慢指针同时往链表尾部移动,
当快指针到达链表尾部的时候,慢指针所指向的就是链表倒数第N个结点
参数:
n:需要删除的倒数第N个结点
"""
fast = self.__head
slow = self.__head
step = 1
tmp = None
if n <= 0 or n > self.__len:
print("超出链表范围")
return
while step < n:
fast = fast.next_node
step += 1
while fast.next_node is not None:
tmp = slow
fast = fast.next_node
slow = slow.next_node
else: # python 特有的语法,当while条件不满足时会执行一次else
if not tmp:
self.__head = self.__head.next_node # 倒数最后一个结点(第一个结点)
self.__len -= 1
return
tmp.next_node = slow.next_node
def find_mid_node(self):
"""查找链表中的中间结点(奇数返回中间,偶数返回左半边元素)
思想:
设置快、慢两种指针,快指针每次跨两步,慢指针每次跨一步,则当快指针到达链表尾部的时候,慢指针指向链表的
中间结点
返回:
一个新的Node结点
"""
if self.__head is None:
print("空链表")
return
fast = self.__head
slow = self.__head
while fast.next_node is not None and fast.next_node.next_node is not None:
slow = slow.next_node
fast = fast.next_node.next_node
return slow
def reversed_self(self):
"""翻转链表自身"""
if self.__head is None or self.__head.next_node is None:
return
pre = self.__head
cur = self.__head.next_node
while cur is not None:
pre, cur = self.__reversed_with_two_node(pre, cur)
self.__head.next_node = None
self.__head = pre
@staticmethod
def __reversed_with_two_node(pre: Node, cur: Node):
"""翻转两个相邻结点
参数:
pre:前一个结点
cur:当前结点
返回:
(pre,cur):下一个相邻结点的元组
"""
tmp = cur.next_node
cur.next_node = pre
pre = cur
cur = tmp
return pre, cur
def has_ring(self):
"""检查链表当中是否有环
思想:
设置快、慢两种指针,快指针每次跨两步,慢指针每次跨一步,如果快指针没有与慢指针相遇而是顺利到达链表尾部
说明没有环: 否则,存在环
返回:
True:有环
False:没有环
"""
fast = self.__head
slow = self.__head
while fast is not None and fast.next_node is not None:
fast = fast.next_node
slow = slow.next_node
if fast == slow:
return True
return False
def create_node(self, value):
"""创建一个存储value值的Node结点
参数:
value:将要存储在Node结点中的数据
返回:
Node
"""
return Node(value)
def print_all(self):
"""打印当前链表所有结点数据"""
cur = self.__head
if cur is None:
print("当前链表还没有数据")
return
while cur.next_node is not None:
print(str(cur.data) + " --> ", end="")
cur = cur.next_node
print(str(cur.data))
if __name__ == '__main__':
lst = SinglyLinkedList1()
for i in range(10):
lst.insert_to_head(i)
lst.print_all()
# 查找中间结点
node = lst.find_mid_node()
print(node.data)
# 删除倒数第2个结点
lst.delete_last_n_node(2)
lst.print_all()
# 插入一个无效结点
lst.insert_after(None, 10)
# 翻转链表
lst.reversed_self()
lst.print_all()
node = lst.create_node(100)
print(node.data)
class DBListNode:
def __init__(self, x, y):
self.key = x
self.val = y
self.next = None
self.prev = None
class LRUCache:
"""
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。
当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间
哈希表+双向链表
哈希表: 查询 O(1)
双向链表: 有序, 增删操作 O(1)
Author: fan
"""
def __init__(self, capacity: int):
self.capacity = capacity
self.hkeys = {}
# self.top 和 self.tail 作为哨兵结点, 避免越界
self.top = DBListNode(None, -1)
self.tail = DBListNode(None, -1)
self.top.next = self.tail
self.tail.prev = self.top
def get(self, key: int) -> int:
if key in self.hkeys.keys():
# 更新结点顺序
cur = self.hkeys[key]
# 跳出原位置
cur.next.prev = cur.prev
cur.prev.next = cur.next
# 最近用过的置于链表的首部
top_node = self.top.next
self.top.next = cur
cur.prev = self.top
cur.next = top_node
top_node.prev = cur
return self.hkeys[key].val
return -1
def put(self, key: int, val: int):
if key in self.hkeys.keys():
cur = self.hkeys[key]
cur.val = val
# 跳出原来的位置
cur.prev.next = cur.next
cur.next.prev = cur.prev
# 最近用过的置于链表首部
top_node = self.top.next
self.top.next = cur
cur.prev = self.top
cur.next = top_node
top_node.prev = cur
else:
# 增加新节点到首部
cur = DBListNode(key, val)
self.hkeys[key] = cur
# 最近用过的置于链表首部
top_node = self.top.next
self.top.next = cur
cur.prev = self.top
cur.next = top_node
top_node.prev = cur
if len(self.hkeys.keys()) > self.capacity:
self.hkeys.pop(self.tail.prev.key)
# 去掉原来的尾结点
self.tail.prev.prev.next = self.tail
self.tail.prev = self.tail.prev.prev
def __repr__(self):
values = []
p = self.top.next
while p.next:
values.append(str(p.val))
p = p.next
return '->'.join(values)
if __name__ == '__main__':
cache = LRUCache(2)
cache.put(1, 1)
cache.put(2, 2)
print(cache)
cache.get(1)
cache.put(3,3)
print(cache)
cache.get(2)
print(cache)