单链表
---
单链表
单链表和顺序表有何不同?
- 顺序表 通过 顺序存储 实现了 线性结构(逻辑结构)
- 单链表 通过 链式存储 实现了 线性结构
代码定义
本质上Lnode * L 和 LinkList L是一样的,有时为了更好的可读性会特意选择其中一种表示方法
不带头结点的单链表
带头节点的单链表
---一般来说,带头节点的单链表更为常用---
单链表的定义小结
单链表的操作
按位插入(带头结点)
按位插入(不带头结点)
给定结点的后插
T(n)= O(1)
给定结点的前插
- 需要传入头结点,循环遍历找到前驱后再插入,复杂度O(n)
- 下图方法使用了一个小技巧将前插的复杂度优化为O(1)
- 首先申请一个新结点t,将其后插到p后(同后插法)
- 交换p和t中的数据,实现将t作为p前驱的目的
书上的算法同上(新结点s已经申请好了)
按位删除
给定结点的删除
思路同上,可以通过头结点循环遍历找到前驱(时间复杂度O(n)),也可以“偷天换日”,将p的数据复制到新结点t中,free(q),复杂度O(1)
!但是这个技巧在删除操作中存在一个bug,如果p是最后一个节点,下一结点为null,其next拿不到值,因此需要单独编写逻辑通过循环遍历取到前驱结点
从这也能看出单链表的局限性:只允许单向检索
知识小结
按位查找
按值查找
求表长
知识小结
单链表的建立
尾插法
可以直接调用之前的插入函数,每次在表尾处插入,缺点是每次都要从头遍历找到表尾,时间复杂度为O(n^2),可通过设置表尾指针优化
头插法
---建议养成初始化的好习惯,因为内存将一块空间分配给我们时是不会对其中的“脏数据”进行“清扫”的,如果忘记初始化而直接使用其中遗留的旧数据可能会导致意想不到的后果---
tips:头插法在链表的逆置中有重要应用
最后,无论是头插法还是尾插法,核心都是初始化操作和指定位置的后插(头结点后插为头插,尾结点后插为尾插)