📒博客主页:要早起的杨同学的博客
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文所属专栏:【数据结构】
✉️坚持和努力从早起开始!
💬参考在线编程网站:🌐牛客网🌐力扣
🙏作者水平有限,如果发现错误,敬请指正!感谢感谢!
学习链表之前,建议先学习下顺序表哦:
文章目录
一. 链表介绍
1.1 为什么引入链表
- 学习链表之前,先让我们来思考一个问题:
为什么有了顺序表,还需要有链表这样的数据结构呢?
- 顺序表存在的一些问题:
- 顺序表在中间/头部的插入删除,要挪动很多数据,时间复杂度为O(N),效率太低了。
- 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
- 增容一般是一次增长2倍,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们
再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
- 为了更好的解决上述问题,引入了链表。
1.2 链表的概念及结构
- 概念
前面学习的顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,而链表是一种物理存储结构上不连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,可以实现更加灵活的动态内存管理。
- 链表的组成
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。
每个结点包括两个部分:
1、数据域:存储数据元素
2、指针域:存储下一个结点地址
- 链表的物理结构
可以看到,4个节点的地址并不是连续的,链表在物理结构上不一定是线性的,而在逻辑结构上是线性的
- 链表的逻辑结构(想象出来的)
- 注意
1、链式结构在逻辑上是连续的,但在物理上不一定连续
2、链表的节点是在堆上申请出来的
1.3 链表的分类
链表的结构非常多样化
- 单向、双向
- 带头结点、不带头节点(哨兵位的头节点,不存储有效数据)
- 非循环、循环
- 常用的两种结构
二. 无头单向非循环链表的实现
首先新建一个工程( 博主使用的是 VS2019 )
- SList.h(单链表的类型定义、接口函数声明、引用的头文件)
- SList.c(单链表接口函数的实现)
- Test.c(主函数、测试顺序表各个接口功能)
如图:
2.1 单链表的定义
typedef int SLTDataType;
//定义单链表节点
typedef struct SListNode
{
SLTDataType data; //数据域
struct SListNode* next; //指针域
}SListNode;
2.2 动态申请一个节点
//动态申请一个节点
SListNode* BuySListNode(SLTDataType x)
{
SListNode* node = (SListNode*)malloc(sizeof(SListNode));
if (node == NULL) //检查是否开辟成功
{
perror("malloc");
return;
}
node->data = x;
node->next = NULL;
return node;
}
2.3销毁(释放)所有节点
//销毁单链表中所有节点
void SListDestory(SListNode** pphead)
{