数据结构—链表(Linked list)
注:此文档《数据结构与算法之美》的课上学习和自习总结的。属于原创文章,如发现错误,请指出
系列文章
系列文章
什么是数据结构?什么是算法?
数据结构—数组
数据结构—链表
数据结构—栈
数据结构—队列
数据结构—排序
链表(Linked list)
-
概念:
-
是线性表的一种
-
在物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
-
特点:(非连续,非顺序的线性表,插入删除快,查找慢,由指针链接,空间相对于数组开销大)
- 非连续、非顺序
- 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成
- 由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度
- 查找一个节点或者访问特定编号的节点则需要O(n)的时间
- 同时链表由于增加了结点的指针域,空间开销比较大
- 链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
- 频繁的插入删除操作,会导致频繁的内存申请和释放,(java)可能会导致频繁的gc
-
-
链表与数组的区别(重点内容)
- 都是线性表
- 数组依赖下标,链表依赖指针
- 数组需要连续的内存空间,链表不需要(数组需要连续的顺序的内存空间,链表是非连续,和非顺序)
- 数组查找快(指定数组下标),链表插入删除快(指针)
- 数组存储相同大小的数据内存小于链表(链表部分空间存储指针),即内存空间小
-
链表术语:
-
结点:链表通过指针把零散的内存块串联起来,其中零散的内存块称为“结点”
-
后续指针:记录下一个结点的地址的指针叫做后续指针(也称next)
-
头结点:习惯把第一个结点称为头结点
-
尾结点:最后一个结点称为尾结点
单链表
- 概念:
- 单向的链表,访问数据从头结点开始
- 特点
- 链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始
- 尾结点的后续指针不是指向下一个结点,而是一个空地址(null)
循环链表
-
概念:
- 特殊的单链表,尾结点的指针指向头结点,让首尾访问更加方便。
-
特点
- 尾结点的指针不指向空地址,而是指向头结点
- 方便处理环形的结构的数据。如约瑟夫问题
双向链表
- 概念:
- 结点不仅有后续指针指向下一个结点,还有前驱指针prev指向前面的结点
-
特点
- 双向的链表
- 需要更大的空间存储后续指针和前驱指针
- 比单链表更灵活:更容易找到前驱结点和后续结点,插入删除更快
-
删除操作
- 开发情况:
- 删除结点(值等于结点中的值)
- 删除给定指针区域的结点
- 相对于单链表来说可以让我们快速找到前结点和后结点的地址,更做出改变(删除或者插入)
- 在有序的链表中,双向链表的按值查询效率也比单链表高一些,因为我们表可以记录上次查找的位置p,每次查询时确定与p位置的值得大小关系,觉得往前还是往后查找,所以只需要查找单链表一半的数据
- 在java语音中LinkedHashMap就是双链表这种数据结构
- 开发情况:
数组和链表性能大比拼
对比 | 数组 | 链表 |
---|---|---|
插入删除 | O(n) | O(i) |
随机访问(查找) | O(i) | O(n) |
空间占用 | 小 | 大(存储指针) |
内存要求 | 连续,顺序 | 非连续,非顺序 |
动态扩容 | 不支持,固定大小 | 支持,动态扩容 |
CPU缓冲预读 | 连续内存空间,支持 | 不连续存储,没法预读 |
额外知识点
缓存
-
概念:
- 缓存是一座提高数据读取性能的技术
-
特点:
- 有大小限制
- 当缓存快被占满时,清理数据——缓存淘汰策略
-
缓存淘汰策略
- FIFO :先进先出(first in first out)
- LFU:最少使用(least frequently Used)
- 最近最少使用 (least recently Used)
学习链表的方法
-
理解指针的或者引用的含义(C语音:指针,java语音:引用)
-
警惕指针丢失和内存泄漏
题外话:谢谢大家观看,有不足之处欢迎大家一起讨论;码字不易,大家喜欢,麻烦点赞哦。
灵魂三问:
- 有没有觉得技术得不到系统的提升,技术成长慢?
- 有没面试懵逼,升职加薪难?
- 有没有想过去大一点的世界看看?
有期望JAVA技术巩固的、Android知识进阶的、期望升职加薪的、Android面试技巧的、大厂面试真题的;大家可以加我QQ哦:1070800492。我们一起学习,一起进步!
重要的事情说三遍:
- 学习、挣钱、自由
- 学习、挣钱、自由
- 学习、挣钱、自由
疫情当下,唯有自强