线性表——单链表

单链表中,在C语言中用结构指针来描述。
在这里插入图片描述

假设 p 是指向线性表第 i 个元素的指针,
p -> data 表示结点 ai 的数据域。
p -> next 表示结点 ai 的指针域,p -> next 的值是一个指针, 指向第 i + 1个元素。即指向 ai+1的指针。
则如果 p -> data = ai ,那么 p -> next -> data = ai+1在这里插入图片描述

单链表的读取

在线性表顺序存储结构中,计算任意一个元素的存储位置较为容易。

对于单链表实现获取第 i 个元素的数据的操作GetElem, 在算法上,相对要麻烦一些。

获得链表第 i 个数据的算法思路:

  • 声明一个结点 p 指向链表第一个结点,初始化 j 从 1 开始;
  • 当 j < i 时, 就遍历链表,让 p 的指针向后移动,不断指向下一结点, j 累加 1;
  • 若到链表末尾 p 为空, 则说明第 i 个元素不存在;
  • 否则查找成功,返回结点 p 的数据。

实现代码算法如下:
在这里插入图片描述
在这里插入图片描述
即从头开始找,直到找到第 i 个元素为止,因此最坏情况的时间复杂度为 O(n)。
由于单链表的结构中没有定义表长, 所以不能事先知道要循环多少次,因此也就不方便使用for 来控制循环。主要核心“工作指针后移”。

单链表的插入与删除

  • 单链表的插入:
    假设存储元素 e 的结点为 s ,要实现结点 p ,p -> next 和 s 之间逻辑关系的变化, 只需要将结点 s 插入到结点 p 和 p -> next 之间即可。在这里插入图片描述
    只需要让p -> next 和 s -> next 的指针做一点改变即可:

     s->next = p->next ; p->next = s 。
     即让 p 的后继结点改成 s 的后继结点,再把结点 s 变成 p 的后继结点。
    

在这里插入图片描述
两句的顺序不可以交换。插入结点 s 后,链表如图所示。在这里插入图片描述
第 i 个数据插入结点的算法思路:

  • 声明一结点 p 指向链表第一个结点, 初始化 j 从 1 开始;
  • 当 j < i 时, 就遍历链表,让 p 的指针向后移动,不断指向下一结点,j 累加 1 。
  • 若到链表末尾 p 为空,则说明第 i 个元素不存在;
  • 否则查找成功, 在系统中生成一个空结点 s ;
  • 将数据元素 e 赋值给 s -> data;
  • 单链表的插入标准语句 s -> next = p -> next; p -> next = s;
  • 返回成功。

实现代码:
在这里插入图片描述

单链表的删除

设存储元素 ai 的结点为 q, 要实现将结点 q 删除单链表的操作 ,其实就是将它的前继结点的指针绕过,指向它的后继结点即可,
在这里插入图片描述
单链表第 i 个删除结点的算法思路:

  • 声明一结点 p 指向链表第一个结点, 初始化 j 从 1开始;
  • 当 j < i 时 ,就遍历链表, 让 p 的指针向后移动,不断指向下一结点, j 累加 1。
  • 若到链表末尾 p 为空,则说明第 i 个元素不存在;
  • 否则查找成功,将欲删除的结点 p -> next 赋值给 q;
  • 单链表的删除标准语句 p -> next = q - > next;
  • 将 q 结点中的数据赋值给 e ,作为返回;
  • 释放 q 结点;
  • 返回成功

实现代码:
在这里插入图片描述

从整个算法来说,我们很容易推导出:它们的时间复杂度都是 O(n),如果在我们不知道第 i 个元素的指针位置,单链表数据结构在插入和删除操作上,与线性表的顺序存储结构是没有太大优势的。但如果,我们希望从第 i 个位置,插入10 个元素 ,那么单链表的效率优势就会非常明显。

单链表的整表创建

创建一个单链表的过程就是一个动态生成链表的过程。即从“空表”的初始状态起,依次建立各元素结点 ,并逐个插入链表。

单链表整表创建思路:

  • 声明一结点 p 和计数器变量 i ;
  • 初始化一空链表 L ;
  • 让 L 的头结点的指针
  • 循环:
    -生成一新结点赋值给 p;
    -随机生成一数字赋值给 p 的数据域 p -> data;
    -将 p 插入到头结点与前一新结点之间。

实现代码算法如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 上图是使用插队的方法,始终让新结点在第一的位置,即头插法。
  • 也可以把新结点都插在终端结点的后面,尾插法。
    在这里插入图片描述
    在这里插入图片描述
    L是指整个单链表,而 r 是指向尾结点的变量, r 会随着循环不断地变化结点,而 L 则是随着循环增长为一个多结点的链表。

单链表的整表删除

删除算法思路:

  • 声明一个结点 p 和 q;
  • 将第一个结点赋值给 p ;
  • 循环:
    -将下一个结点赋值给 q ;
    -释放 p;
    -将 q 赋值给 p;

在这里插入图片描述

单链表结构与顺序存储结构优缺点

在这里插入图片描述

  • 若线性表需要频繁查找,很少进行插入和删除操作是,宜采用顺序 存储结构。
  • 若需要频繁插入和删除时,宜采用单链表结构。比如说游戏开发中,对于用户注册的个人信息,除了注册时插入数据外,绝大多数情况都是读取,所以考虑用顺序存储结构。而游戏玩家的武器或装备列表,随着游戏过程,可能会随时增加或删除,此时可以用单链表结构,(仅作为举例)。
  • 当线性表中的元素个数变化比较大或者根本不知道有多大时,最好用单链表结构,这样可以不需要考虑存储空间的大小问题。而如果实现知道大致长度,用顺序存储结构效率会高很多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值