常用缓存策略
FIFO、LFU、LRU
如何用链表实现LRU?
链表相关知识
结点、后继指针(next)、头结点、尾结点、前驱结点
循环链表、双向链表(next、pre)
PS:在“删除某个指针指定的节点”或者“在某个指定节点前插入”这种操作中,双向链表复杂度是O(1),而单链表是O(n); 在“删除特定值的节点”的操作中,二者复杂度都是O(n)
链表在插入删除上,比数组优秀;而在随机访问上,数组为O(1),链表为O(n)
链表的内存相比数组会翻倍
此外,数组的连续内存机制,可以利用CPU的缓存机制,预读数据,而链表做不到
此外,数组需要占用一整块空间,所以申请时过大,可能导致内存不足;过小可能后续开辟新空间时,需要拷贝原数组,很耗时。
用链表实现LRU
思路,维护一个有序单链表,越靠近尾部的节点,是越久之前访问的,当有新的数据被访问,从链表头开始顺序遍历。
1.如果此数据存在,则读取,然后删除原位置节点,在插入到头部
2.如果不存在
2.1 如果缓存未满,则将此节点直接插入链表头部
2.2 如果缓存已满,则删除尾结点,插入头结点
由于必定会遍历链表,所以缓存访问的时间复杂度为O(n)
// 链表节点的C++定义法
struct ListNode
{
int data;
struct ListNode *next;
};
通过引入**散列表(Hash table)**可以将复杂度降到O(1)
如何写链表
一、理解指针/引用的含义
将变量赋值给指针,就是将变量的地址赋值给指针,即,指针中保存的是变量的内存地址,通过该指针能够找到变量。
二、警惕指针丢失和内存泄漏
合理安排指针改变的顺序,防止指针丢失
删除链表节点时,手动释放内存空间
三、利用哨兵减缓实现难度
此处的哨兵指的就是“头指针”,即不参与数据保存一个的一个头结点
四、多检查边界
链表为空/仅一个节点/仅两个节点时能否正常工作?
代码能否正常处理头尾节点?
五、画图辅助
课后练习
单链表翻转
链表中环检测
有序链表合并
删除倒数第n个节点
求链表中间节点
PS:typedef关键字在C和eC++中的区别
C++中可以不用typedef定义结构体,C中可能会编译不通过
https://blog.csdn.net/sjxbf/article/details/6330177
PS:解引用、引用、取地址运算
https://blog.csdn.net/qq_38556370/article/details/80631725
(*p).成员名
p->成员名