链表对指针的操作要求不低
链表的概念
什么是链表
官方概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
解释一下
通俗的链表解释是 通过箭头链接的
就如同锁链一样链接起来
两个节点之间的空间都没有任何联系
比如 节点A 和节点 B的空间 本来没有任何联系
但是两者通过 next 的指针
从节点 A 能够访问到节点 B ,然后能够一直向下访问知道 空指针
但是实际上
那个箭头是不存在的,是用来理解用的
实际存在的只有地址,访问过程中调用的也是指针(地址)
从图片的分析来看
一个节点要被分成两半
一般用来储存数据,一般用来储存下一个节点的地址
所以我们程序上的指针的定义可以这样写
typedef int Datatype;
typedef struct SingleList
{
Datatype Data;
struct SingleList* next;
}SLTNode;
但是下面定义是不对的
typedef int Datatype;
typedef struct SLTNode
{
Datatype data;
SLTNode* next;
}SLTNode;
因为在内容上 next 的定义在 SLTNode 的 typedef 重命名前,语法错误
链表的特性
链表有什么独特的地方?
所谓独特,必须有所对比,这里取顺序表进行对比
不同点 | 链表 | 顺序表 |
---|---|---|
存储空间 | 物理上空间连续 | 逻辑连续,物理上不一定连续 |
随机访问 | 可以使用下标直接访问 | 必须遍历找到对应地址 |
任意位置插入(重要) | 需要搬移数据 | 只需要修改指向 |
容量 | 容量不足的时候需要扩容 | 不需要扩容 |
使用场景 | 元素频繁访问 | 任意位置的插入和删除 |
所以链表的优点
- 插入删除很高效
- 寻找元素速度慢
- 空间利用率高,不需要扩容
链表的功能(最重要)
我们如何利用链表存储数据和调用数据?
链表本身就是一个数据结构,就需要定义定义一个数据结构,并且实例化
数据结构用来存放取出数据,访问数据
最终要销毁数据结构
所以有如下要求
定义和初始化
第一个问题,链表是由什么组成的?
是由 内容为存储的数据 和 指向下一个节点的 节点组成
第1. 1 的问题是 节点的类型 如何定义?
用程序的话说就是:
typedef int STDatatype;
struct ListNode
{
STDatatype data;
struct ListNode* next;
};
typedef struct ListNode SLTNode;
但是只有一个节点的结构是不足的
就像只知道有 int 这个类型但是没有数据一样,光有空壳但是没有血肉
如何在 Node 里面填充血肉?
第1.2 个问题:如何创建节点
主要步骤是:
- 开辟一个节点空间
- 在节点空间中存放数据
对于程序来说就是:
SLTNode* BuyNewNode(Datatype x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if(newnode == NULL)
{
perror("malloc failed");
exit(-1);//故障退出
}
newnode->next = NULL;
newnode->data = x;
return newnode;
}
第1.3 个问题: 如何初始化一个链表
我们使用单链表的时候,只要拿到链表的头就能够操作了
所以因为头的特殊性,我们单独定义一个名字
typedef SLTNode SLTHead;
随后进行链表的创建
步骤
- 循环创建节点
- 将节点链接起来
细节
- 当创建第一个节点时,头结点改变指向第一个节点,之后的节点头结点位置不再改变
//创建 n 个节点
SLTHead* BuildList(int n )
{
SLTHead* phead = NULL;
SLTNode* pcur = phead;
for(int i = 0;i<n;i++)
{
SLTNode* newnode = BuyNewNode(i