码迷,mamicode.com
首页 > 其他好文 > 详细

链表(Linked List)

时间:2021-03-08 13:20:35      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:开始   习惯   use   lru   http   过程   约瑟夫   链表实现   保存   

内容摘自:数据结构与算法之美

链表

链表并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用。

单链表

  • 链表通过指针将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。
  • 为了将所有的结点串起来,每个链表的结点不仅要存储数据,还需要记录下一个结点的地址。我们将这个记录下个节点地址的指针叫作后继指针

如图所示
技术图片

我们习惯把第一个结点叫头结点,把最后一个结点叫尾结点。尾结点指针指向一个空地址NULL。

链表支持数据的查找、插入和删除操作,

插入、删除操作如下图所示。时间复杂度O(1)。
技术图片

查询操作智能一个一个的往下找,所以随机查询的时间复杂度为O(n)。

循环链表

循环链表是一种特殊的单链表。循环链表的尾结点指针是指向链表的头结点。
技术图片

约瑟夫问题就可以用循环链表解决。

双向链表

双向链表支持两个方向,每个结点有一个后继指针 next 指向后一个结点,还有一个前驱指针 prev 指向前一个结点。
技术图片

双向链表需要额外的两个空间存储 next 和 prev 结点的地址。因此,存储数据一定的情况下,双向链表会占用更多的内存空间。

从结构上看,prev 结点指针存放的是前驱结点的地址,因此双向链表的查询的时间复杂度为 O(1),即可以根据地址找到结点。相对的,插入、删除等操作也要比单链表简单。

删除操作是如何比单链表高效的

实际开发中,从链表中删除一个数据一般就两种情况:

  1. 删除节点中“值等于某个给定值”的结点
  2. 删除给定指针指向的结点。

分析思路
第一种情况,单向链表、双向链表都需要依次遍历对比,直到找到该值,再删除。
第二种情况
已经找到了要删除的结点,但是根据删除操作,还需要知道被删除结点的前驱结点。
因此,为了找到前驱结点,单链表还需要进行一次遍历,直到找到p->next=q。但是对于双向链表则不用,因为 prev 已经保存了前驱结点的地址。

对于查询操作
对于一个有序的链表来说,双向链表的按值查询效率也要高一些。
因为对于位置 p,可以根据要查询的值与 p 结点的值之间的大小关系,决定向前查询还是向后查询。

实际开发过程中,要掌握用空间换时间的设计思想。

双向循环链表

技术图片

LRU 缓存淘汰算法

常见缓存淘汰策略

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

使用链表实现 LRU 缓存淘汰算法。

思路分析
维护一个有序单链表,结点顺序插入,越靠后的是越早之前访问的,越靠前越新。
当一个新数据被访问时,开始遍历链表。

  1. 若访问的数据在链表中,则遍历到该结点并从原位置删除,插入到链表头。
  2. 若访问的数据不在链表中
    i. 若缓存未满,则将结点插入链表头。
    ii. 若缓存已满,删除最后的结点,将被访问数据结点插入链表头。

链表(Linked List)

标签:开始   习惯   use   lru   http   过程   约瑟夫   链表实现   保存   

原文地址:https://www.cnblogs.com/zzfan/p/14491831.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!