数据结构--单链表的插入、删除、查找详解

1 线性表

1.1 单链表
1.1.1 单链表的定义
  • 链式存储结构:结点在存储器的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻

  • 线性表的链式表示又称为非顺序映像或链式映像

  • 结点只有一个指针域的链表,称为单链表或线性链表,指针域指向下一个结点的存储地址。

  • 结点有两个指针域的链表称为双链表,除了指向后继元素的存储地址,还有指向前驱元素的存储地址

  • 首尾相接的链表称为循环链表

单链表和顺序表的区别:

  • 顺序表是随机存取的方法,链表是顺序存取的方法,访问时需要依次向后顺序扫描其他结点
  1. 第一种写法:合并式

typedef struct LNode{ //定义单链表结点类型(结点)
ElemType data; //每个节点存放一个数据元素(数据域)
struct LNode*next; //指针指向下一个结点的存储位置(指针域)
}LNode,*LinkList;

  1. 第二种写法:拆分式

struct LNode{

ElemType data;

struct LNode *next;}

typedef struct LNode LNode;

typedef struct LNode*LinkList;

注意:

我们来做个等价替换:

  • 已知: LNode = struct LNode

  • 那么 LNode* = struct LNode *

  • 又已知: LinkList = struct LNode *

  • 所以: LinkList ≡ LNode* (完全等价)

  • LNode,*LinkList:定义了两个别名,Lnode 是 struct student 的别名,代表单个结点的类型; LinkList 是 struct student * 的别名,代表指向结点的指针类型,也就是链表头指针的类型。

  • 比如 typedef struct student *LinkList; ,意思就是"把 struct student * 这个指针类型,别名叫 LinkList "。所以 LinkList L; 就相当于 struct student *L;L就是一个指向链表第一个结点的指针(头指针)

  • 强调这是一个单链表使用LinkList

  • 强调这是一个结点使用LNode*

例题:

  • 本质:用 typedef 给一个「匿名结构体」起别名 ElemType ,这个结构体用来存储单个学生的完整信息。

  • 作用:把「学生数据」封装成一个统一的类型 ElemType ,后续链表只需要操作这个通用类型,不用关心里面具体是学号、姓名还是成绩。

1.1.2 头指针、头结点、首元结点
  • 单链表由头指针唯一确定,因此单链表可以用头指针的名字来命名,比如头指针叫L,那么单链表就可以叫单链表L。头指针存储了下一个结点的存储地址,只要我们有头指针就可以顺藤摸瓜,找到其他元素的地址。
1.1.3 单链表的初始化

原理:头结点的指针域为空,后面没有元素

  • Status 本质就是用 typedef 给基本数据类型(通常是 int )起的别名,它本身不是新类型
1.1.4 单链表的基本操作
算法1:判断链表是否为空

空表:链表中无元素,称为空链表,头指针和头节点仍然在

算法思路:判断头节点指针域是否为空

算法2:销毁单链表

算法思路:从头指针开始,依次释放所有节点。逻辑是用临时指针p保存当前节点,让L先移动到下一个节点,再删除p指向的节点,循环执行直到所有节点(包括头节点)都被释放销毁。

  • 步骤1:p = L→ 把当前要删除的节点地址存到临时指针 p 里,这样后续即使 L 移动,也能通过 p 找到要删除的节点。

  • 步骤2:L = L->next → 让 L 移动到下一个节点,这一步很关键,否则删除当前节点后,就找不到后续的节点了。

  • 步骤3: delete p → 释放 p 指向的节点内存,完成当前节点的销毁。

算法3:清空链表

算法思路:依次释放所有节点,并将头节点指针域设置为空。链表仍存在,但链表中无元素,成为空链表,头指针和头节点仍然在。区别是销毁链表头指针和头结点也被销毁。

算法4:求单链表的表长

算法思路:从首元结点开始,依次计数所有结点

C++ 复制代码
//重要操作:
P=L;//P指向头结点
s=L->next;//s指向首元结点
p=p->next;//p指向下一结点
算法5:取值--取单链表中第i个元素的内容(带头结点)
  • 顺序表是随机存取的方法,链表是顺序存取的方法,访问时需要依次向后顺序扫描其他结点

算法步骤:

算法6:按值查找--根据指定数据获取该数据的所在位置(地址)

算法步骤:

  • 返回地址
  • 返回位置序号
算法7:插入--在第i个结点前插入值为e的新结点

步骤:

算法8:删除--删除第i个结点

步骤:

1.1.5 单链表的查找、插入、删除算法时间效率分析
1.1.6 单链表的建立--头插法

步骤:

1.1.7 单链表的尾插法


在链表中设置头结点有什么好处?

  • 便于首元结点的处理,首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其他位置一致,无需进行特殊处理
  • 便于空表和非空表的统一处理,无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了

总结:

相关推荐
疯狂打码的少年2 小时前
【Day13 Java转Python】装饰器、生成器与lambda——Python的函数式“三件套”
java·开发语言·python
牢姐与蒯2 小时前
c++进阶之继承
c++
_李小白2 小时前
【OSG学习笔记】Day 53: Text3D( 三维文字)
笔记·学习·3d
石榴树下的七彩鱼2 小时前
Python OCR 文字识别 API 接入完整教程
开发语言·人工智能·后端·python·ocr·api·图片识别
会飞的胖达喵2 小时前
基于qt开发的RedisDesk
开发语言·qt
信看2 小时前
看所有网卡参数,确认 RM520N-GL 网卡
开发语言·python
油炸自行车2 小时前
【Qt】运行 `windeployqt.exe` 打包Qt发布包,遇到警告的解决方法 (Warning: Cannot find any.....)
开发语言·qt·vs·打包·windeployqt·软件部署
yu85939582 小时前
C++ 虚拟磁盘与虚拟光驱实现
开发语言·c++
阿凤212 小时前
后端返回数据流的格式
开发语言·前端·javascript·uniapp