单链表

---

单链表

image-20210405193211177

单链表和顺序表有何不同?

image-20210405193452272

  • 顺序表 通过 顺序存储 实现了 线性结构(逻辑结构)
  • 单链表 通过 链式存储 实现了 线性结构

代码定义

image-20210405194146890

image-20210405194527299

本质上Lnode * L 和 LinkList L是一样的,有时为了更好的可读性会特意选择其中一种表示方法

image-20210405194808550

不带头结点的单链表

image-20210405195252832

带头节点的单链表

image-20210405195343570

---一般来说,带头节点的单链表更为常用---

image-20210405195537646

单链表的定义小结

image-20210405200023231

单链表的操作

image-20210405200121476

按位插入(带头结点)

image-20210405201549848

按位插入(不带头结点)

image-20210405202214429

给定结点的后插

T(n)= O(1)

image-20210405202615431

给定结点的前插

  • 需要传入头结点,循环遍历找到前驱后再插入,复杂度O(n)

image-20210405202938710

  • 下图方法使用了一个小技巧将前插的复杂度优化为O(1)
    1. 首先申请一个新结点t,将其后插到p后(同后插法)
    2. 交换p和t中的数据,实现将t作为p前驱的目的

image-20210405203514834

书上的算法同上(新结点s已经申请好了)

image-20210405204325601

按位删除

image-20210405205119160

给定结点的删除

思路同上,可以通过头结点循环遍历找到前驱(时间复杂度O(n)),也可以“偷天换日”,将p的数据复制到新结点t中,free(q),复杂度O(1)

image-20210405205458300

!但是这个技巧在删除操作中存在一个bug,如果p是最后一个节点,下一结点为null,其next拿不到值,因此需要单独编写逻辑通过循环遍历取到前驱结点

从这也能看出单链表的局限性只允许单向检索

知识小结

image-20210405210326911

按位查找

image-20210405211929909

按值查找

image-20210405212536282

求表长

image-20210405212723909

知识小结

image-20210405212918736

单链表的建立

尾插法

image-20210405213020297

可以直接调用之前的插入函数,每次在表尾处插入,缺点是每次都要从头遍历找到表尾,时间复杂度为O(n^2),可通过设置表尾指针优化

image-20210405213503317

image-20210405214450367

头插法

image-20210405215012960

---建议养成初始化的好习惯,因为内存将一块空间分配给我们时是不会对其中的“脏数据”进行“清扫”的,如果忘记初始化而直接使用其中遗留的旧数据可能会导致意想不到的后果---

tips:头插法在链表的逆置中有重要应用

最后,无论是头插法还是尾插法,核心都是初始化操作指定位置的后插(头结点后插为头插,尾结点后插为尾插)

原文地址:https://www.cnblogs.com/potofsalt/p/14619684.html