1. 链表的概念
顺序表 → 静态存储分配 → 事先确定容量
链表 → 动态存储分配 → 运行时分配空间
1.1 单链表:线性表的链接存储结构
存储思想:用一组任意的存储单元存放线性表的元素——不连续、零散分布
1.2 单链表存储特点
- 逻辑次序和物理次序不一定相同
- 元素之间的逻辑关系用指针表示
单链表是由若干结点构成的,节点只有一个指针域
1.3 单链表的结点结构
- data:数据域,存储数据元素
- next:指针域,存储指向后继结点的地址
- Node st; 等价于 struct node st;
- Link p; 等价于 struct node *p; (p=&st;)
- Node变成了一个类型,声明一个结构体变量;Link也变成了一个类型,用来声明一个指向结构体的指针
1.4 如何申请一个结点?
p = (Link)malloc(sizeof(Node)); 等价于 p = (struct node *)malloc(sizeof(Node));
1.5 如何引用数据元素?
(*p).data / p -> data
1.6 如何引用指针域?
p -> next
1.7 什么是存储结构?
数据元素之间的逻辑关系的表示,将实际存储地址抽象。
头指针:指向第一个结点的地址
尾标志:终端结点的指针域为空
空表:head=NULL
如何将空表与非空表统一?——引入头结点
头结点:在单链表的第一个元素结点之前附设一个类型相同的节点
2. 单链表的实现
2.1 单链表的遍历操作
操作接口:void displayNode(Link head);
p = p->next语句改成 p++ 能否完成指针后移? 不可以!
链表中结点的存储不是连续的,是零散的!
2.2 求单链表的元素个数
操作接口:int length(Link head);
2.3 单链表的查找操作
2.4 单链表的插入操作
操作接口:void insertNode(Link head, int i, DataType x);
2.5 创建一个单链表——头插法
操作接口:Link newList(DataType a[], int n);
头插法:将待插入结点插在头结点的后面
2.6 创建一个单链表——尾插法
操作接口:Link newList(DataType a[], int n);
尾插法:将待插入结点插在终端结点的后面
每次创建一个结点时,将结点数据域指针域全部初始化,指针域初始化为空
2.7 单链表节点的删除
操作接口:bool deleteNode(Link head, DataType x);
2.8 单链表的释放
操作接口:void clearLink(Link head);
3. 循环链表
将单链表的首尾相接,将终端结点的指针域由空指针改为指向头结点,构成单循环链表,简称循环链表。
循环链表的特点:没有明显的尾端 → 如何避免死循环?——修改循环条件
循环条件:(其他操作和单链表一样,除了循环退出条件)
p != NULL → p != head
p->next != NULL → p->next != head
4. 双向链表
在单链表的每个结点中再设置一个指向其前驱结点的指针域。(占用更多的存储空间)
结点结构:
- data:数据域,存储数据元素
- prior:指针域,存储该节点的前趋结点地址
- next:指针域,存储该节点的后趋结点地址
参考:懒猫老师(数据结构入门)