[第三章] 链表

注:此专栏内容主要参考极客时间-数据结构与算法之美

1. 概念

链表与数组相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用;
[第三章] 链表_第1张图片
常见的三类链表:单链表、双向链表、循环链表


2.链表特点

  • 链表中插入或者删除一个数据,我们并不需要为了保持内存的连续性而搬移结点,因为链表的存储空间本身就不是连续的。所以,在链表中插入和删除一个数据是非常快速的。
  • 链表要想随机访问第 k 个元素,就没有数组那么高效了,,而是需要根据指针一个结点一个结点地依次遍历,直到找到相应的
    结点。
  • 链表随机访问的性能没有数组好,需要 O(n) 的时间复杂度

3. 单链表

[第三章] 链表_第2张图片
第一个结点叫作头结点,把最后一个结点叫作尾结点
头结点用来记录链表的基地址。 尾节点指针指向的是一个空地址Null;


4.循环链表

循环链表的尾结点指针是指向链表的头结点。
[第三章] 链表_第3张图片


5.双向链表

双向链表,支持两个方向,每个结点不止有一个后继指针 next 指向后面的结点,还有一个前驱指针 prev 指向前面的结点。
[第三章] 链表_第4张图片

  • 双向链表可以支持 O(1) 时间复杂度的情况下找到前驱结点,正是这样的特
    点,也使双向链表在某些情况下的插入、删除等操作都要比单链表简单、高效;
  • LinkedHashMap就是双向链表的结构;
  • 双向循环链表
    [第三章] 链表_第5张图片

6.数组与链表

  1. 时间复杂度
    [第三章] 链表_第6张图片

  2. 数组简单易用,使用的是连续的内存空间,可以借助 CPU 的缓存机制,访问效率更高。而链表在内存中并不是连续存储,所以对 CPU 缓存不友好,没办法有效预读;

  3. 链表天然支持动态扩容


7.常见的缓存淘汰策略

先进先出策略 FIFO(First In,FirstOut)
最少使用策略 LFU(Least Frequently Used)
最近最少使用策略 LRU(Least Recently Used)

8.链表实现LRU思路

  1. 维护一个链表,保存要被调用的数据,数量是n。其中,越“早”被使用数据,越排在链表尾部;
  2. 当有一个数据被使用时,先与链表中保存的数据进行比较
  • 如果数据已存在链表,将数据挪到链表头部;
  • 如果数据不存在链表,看链表是否已满,如果已满,对链表尾部进行删除,如果未满,插入链表头部;
  1. 不管链表是否满了,都需要遍历与链表中的原数据进行比较,所以时间复杂度是O(n)

9.编写链表代码注意点

  • 如果链表为空时,代码是否能正常工作?
  • 如果链表只包含一个结点时,代码是否能正常工作?
  • 如果链表只包含两个结点时,代码是否能正常工作?
  • 代码逻辑在处理头结点和尾结点的时候,是否能正常工作?

10.数组、链表代码练习(待续)

  • 单链表判断回文字
  • 单链表反转
  • 链表中环的检测
  • 两个有序的链表合并
  • 删除链表倒数第 n 个结点
  • 求链表的中间结点

你可能感兴趣的:(数据结构与算法,链表)