五花八门的链表结构
-
链表的主要应用:LRU 缓存淘汰算法
-
缓存:为了提升读性能的组件,通常用于高速存储中
-
缓存的栗子:CPU 缓存、数据库缓存、浏览器缓存等等
-
缓存淘汰策略:
-
先进先出策略 FIFO 使用队列\
-
最少使用策略 LFU 有序队列\
-
最近最少使用策略 LRU 链表\
-
-
-
常见的链表:单链表、双向链表和循环链表
-
链表组成:节点+后继指针
- 头结点 记录基地址
- 尾节点 指向一个空地址
-
单链表
- 优点:在链表中插入和删除元素的时间复杂度都是o(1) 这点优于数组
- 缺点:不支持随机访问,查询复杂度o(n)
-
循环链表
- 与单链表的区别是 循环链表的尾节点指向链表的头节点
- 简洁的完成约瑟夫问题 todo
-
双向链表
-
有后继指针和前继指针
-
相比于单链表增加向前指针,但是支持双向遍历
-
特点
-
双向链表可以支持 O(1) 时间复杂度的情况下找到前驱结点,在插入和删除都会更加简单(不需要两个指针)可以直接获取前继节点\
-
还可以从临时元素开始向前向后查找
-
-
Java中的LinkedHashMap 空间换时间的思想 类似的还有缓存
-
-
双向循环链表
\
链表 VS 数组性能大比拼
| 数组 | 链表 |
|---|---|
| 连续的内存空间可以利用CPU的缓存机制,预读数据 | 零散的内存块 |
| 固定大小,无法利用内存碎片 | 可以利用内存碎片 |
| 更加节省内存空间 | 增加内存空间,造成内存碎片,可能导致频繁的GC |
\
\
解答开篇
-
如何利用链表实现一个有序单列表
- 维护一个有序链表,头部节点是新访问的,尾部节点是最早访问的
- 新增一个元素,如果在队列中则更新到头部,否则直接插入头部
- 如果缓存已满,则删除尾部元素
- 缓存访问的时间复杂度为 O(n)\
-
引入散列表将访问复杂度降到O(1)
总结
- 链表:单链表,双向链表,循环链表,双向循环链表
- 和数组相比,链表更适合插入、删除操作频繁的场景,查询的时间复杂度较高