1 线性表

1.1 单链表
1.1.1 单链表的定义
-
链式存储结构:结点在存储器的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻
-
线性表的链式表示又称为非顺序映像或链式映像
-
结点只有一个指针域的链表,称为单链表或线性链表,指针域指向下一个结点的存储地址。
-
结点有两个指针域的链表称为双链表,除了指向后继元素的存储地址,还有指向前驱元素的存储地址
-
首尾相接的链表称为循环链表
单链表和顺序表的区别:

- 顺序表是随机存取的方法,链表是顺序存取的方法,访问时需要依次向后顺序扫描其他结点
- 第一种写法:合并式
typedef struct LNode{ //定义单链表结点类型(结点)
ElemType data; //每个节点存放一个数据元素(数据域)
struct LNode*next; //指针指向下一个结点的存储位置(指针域)
}LNode,*LinkList;
- 第二种写法:拆分式
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 单链表的尾插法


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