数据结构之单链表(超详解)
数据结构之单链表(超详解)
1. 单链表1.1 概念、结构链表也是线性表的一种。概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。(即链表在物理结构上不一定连续,在逻辑结构上一定连续)
1.2 结点每节"车厢"都是独立申请下来的空间,我们称之为“节点/结点”。结点的组成主要有两个部分:
1. 当前结点要保存的数据
数据结构之单链表(超详解)
1.1 概念、结构
链表也是线性表的一种。
概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。(即链表在物理结构上不一定连续,在逻辑结构上一定连续)
1.2 结点
每节"车厢"都是独立申请下来的空间,我们称之为“节点/结点”。
结点的组成主要有两个部分: 1. 当前结点要保存的数据 2. 保存下⼀个结点的地址(指针变量)。
上图指针变量 plist保存的是第一个结点的地址,我们称plist此时“指向”第一个结点,如果我们希望plist“指向”第二个结点时,只需要修改plist保存的内容为0x0012FFA0。 链表中每个结点都是独立申请的(即需要插入数据时才去申请一块结点的空间),我们需要通过指针变量来保存下⼀个结点位置才能从当前结点到下一个结点。
对应实现结点的结构体代码:
1.2.1 链表的性质
- 链式机构在逻辑上是连续的,在物理结构上不一定连续;
- 结点⼀般是从堆上申请的;
- 从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续
结点创建
代码语言:javascript代码运行次数:0运行复制void SLTTest01()
{
SLTode* node1 = (SLTode*)malloc(sizeof(SLTode));
node1->data = 1;
SLTode* node2 = (SLTode*)malloc(sizeof(SLTode));
node2->data = 2;
SLTode* node = (SLTode*)malloc(sizeof(SLTode));
node->data = ;
SLTode* node4 = (SLTode*)malloc(sizeof(SLTode));
node4->data = 4;
将4个节点连接起来
node1->next = node2;
node2->next = node;
node->next = node4;
node4->next = ULL;
SLTPrint(plist);
}
显然我们每次都要一个接一个创建结点,并让结点连接起来过于麻烦。因此,我们可以考虑封装成一个函数,这个函数用来创建结点。
创建结点
需要进行尾插,头插的操作首先需要创建结点
尾插
在尾插的时候需要考虑以下几点:
- 如果为空链表该如何处理
- 如何让两个结点相连
- 如何到尾部结点
头插
相比于尾插,头插不需要考虑链表是否为空的情况,因为只要让新的结点头插到ULL即可
尾删
进行尾删操作需要考虑以下因素:
- 链表是否为空,空的话不能进行尾删
- 遍历链表到尾结点
- 保存尾结点的前一个结点
- 释放尾结点,让前一个结点指向ULL
头删
头删需要考虑以下因素:
- 链表是否为空
- 保存第二个有效结点
- 释放第一个有效结点,让pphead指向第二个有效结点
指定位置之前插入数据
- 链表是否为空
- 指定位置值的结点是否存在
- 如果指定位置的结点时头节点,则头插即可
- 遍历链表到指定结点的前一个结点
指定位置之后插入数据
- 链表是否为空
- 指定位置结点是否存在
- 指定位置结点是否是头结点
- 遍历链表到pos结点的前一个结点
- 释放pos结点
Slist.h
代码语言:javascript代码运行次数:0运行复制#define _CRT_SECURE_O_WARIGS 1
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
//针对顺序表:中间/头部插入效率低下、增容降低运行效率、增容造成空间浪费
//因此有了单链表
//链表也是线性表的一种
//链表是由一个一-个的节点组成
//组成:数据 指向下一个节点的指针
typedef int DataType;//可能存储整形,字符型等等
typedef struct Slistode
{
DataType data;//节点数据
struct Slistode* next;//指向下一个节点的指针
}SLTode;
//链表的打印
void SLTPrint(SLTode* phead);
//创建节点
SLTode* SLTBuyode(DataType x);
//尾插
void SLTPushBack(SLTode** pphead, DataType x);
//头插
void SLTPushFront(SLTode** pphead, DataType x);
//尾删
void SLTPopBack(SLTode** pphead);
//头删
void SLTPopFront(SLTode** pphead);
//查
SLTode* SLTFind(SLTode* phead, DataType x);
//在指定位置之前插入数据
void SLTInsert(SLTode** pphead, SLTode* pos, DataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTode* pos, DataType x);
//删除pos节点
void SLTErase(SLTode** pphead, SLTode* pos);
//删除pos后节点
void SLTEraseAfter(SLTode* pos);
//销毁链表
void SLTDesTroy(SLTode** pphead);
代码语言:javascript代码运行次数:0运行复制
#define _CRT_SECURE_O_WARIGS 1
#include"Slist.h"
//链表的打印
void SLTPrint(SLTode* phead)
{
SLTode* pcur = phead;
while (pcur)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("ULL\n");
}
//创建节点
SLTode* SLTBuyode(DataType x)
{
SLTode* newnode = (SLTode*)malloc(sizeof(SLTode));
if (newnode == ULL)
{
perror("malloc fail!");
exit(1);
}
//创建成功
newnode->data = x;
newnode->next = ULL;
return newnode;
}
//尾插
void SLTPushBack(SLTode** pphead, DataType x)
{
assert(pphead);
//空链表和非空链表
SLTode* newnode = SLTBuyode(x);
//如果是空链表
if (*pphead == ULL)
{
*pphead = newnode;
}
else {
//尾节点
SLTode* ptail = *pphead;
while (ptail->next)
{
ptail = ptail->next;
}
//ptail指向的就是尾节点
ptail->next = newnode;
}
}
//头插
void SLTPushFront(SLTode** pphead, DataType x)
{
assert(pphead);
SLTode* newnode = SLTBuyode(x);
newnode->next = *pphead;
*pphead = newnode;
}
//尾删
void SLTPopBack(SLTode** pphead)
{
//链表不能为空
assert(pphead && *pphead);
//链表只有一个节点
if ((*pphead)->next == ULL) //-> 优先级高于*
{
free(*pphead);
*pphead = ULL;
}
else {
//链表有多个节点
SLTode* prev = *pphead;
SLTode* ptail = *pphead;
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
free(ptail);
ptail = ULL;
prev->next = ULL;
}
}
//头删
void SLTPopFront(SLTode** pphead)
{
assert(pphead && *pphead);
SLTode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
//查
SLTode* SLTFind(SLTode* phead, DataType x)
{
SLTode* pcur = phead;
while (pcur)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
//pcur == ULL
return ULL;
}
//在指定位置之前插入数据
void SLTInsert(SLTode** pphead, SLTode* pos, DataType x)
{
assert(pphead && *pphead);
assert(pos);
SLTode* newnode = SLTBuyode(x);
//若pos == *pphead 说明是头插
if (pos == *pphead)
{
SLTPushFront(pphead, x);
}
else {
SLTode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
newnode->next = pos;
prev->next = newnode;
}
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTode* pos, DataType x)
{
assert(pos);
SLTode* newnode = SLTBuyode(x);
//先连接后面在前面
newnode->next = pos->next;
pos->next = newnode;
}
//删除pos节点
void SLTErase(SLTode** pphead, SLTode* pos)
{
assert(pphead && *pphead);
assert(pos);
//pos是头节点
if (pos == *pphead)
{
SLTode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
else
{
//pos不是头节点
SLTode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = ULL;
}
}
//删除pos后节点
void SLTEraseAfter(SLTode* pos)
{
assert(pos && pos->next);
SLTode* del = pos->next;
pos->next = del->next;
free(del);
del = ULL;
}
//销毁链表
void SLTDesTroy(SLTode** pphead)
{
assert(pphead && *pphead);
SLTode* pcur = *pphead;
while (pcur)
{
SLTode* next = pcur->next;
free(pcur);
pcur = next;
}
//pcur为ULL
*pphead = ULL;
}
代码语言:javascript代码运行次数:0运行复制
#define _CRT_SECURE_O_WARIGS 1
#include"Slist.h"
//链表是由一个一个的节点组成
//创建几个节点
//第一个节点 *plist <---> **pphead
//指向第一个节点的指针 plist <---> *pphead
//指向第一个节点的指针的地址 &plist <---> pphead
void SLTTest01()
{
//SLTode* node1 = (SLTode*)malloc(sizeof(SLTode));
//node1->data = 1;
//SLTode* node2 = (SLTode*)malloc(sizeof(SLTode));
//node2->data = 2;
//SLTode* node = (SLTode*)malloc(sizeof(SLTode));
//node->data = ;
//SLTode* node4 = (SLTode*)malloc(sizeof(SLTode));
//node4->data = 4;
//将4个节点连接起来
//node1->next = node2;
//node2->next = node;
//node->next = node4;
//node4->next = ULL;
//调用链表的打印
SLTode* plist = ULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, );
SLTPushBack(&plist, 4);
SLTPushFront(&plist, 5);
SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPopBack(&plist);
//SLTPopBack(&plist);
SLTPopBack(&plist);
SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPopFront(&plist);
SLTPrint(plist);
//测试查
SLTode* find = SLTFind(plist, 5);
if (find == ULL)
{
printf("没有到\n");
}
else {
printf("到了\n");
}
SLTInsert(&plist, find, 6);
//SLTErase(&plist, find);
//SLTEraseAfter(find);
//SLTErase(&plist, find);
SLTPrint(plist);
SLTDesTroy(&plist);
SLTPrint(plist);
}
int main()
{
SLTTest01();
return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-01-2,如有侵权请联系 cloudcommunity@tencent 删除链表数据指针数据结构plist #感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上传时间: 2025-07-18 23:22:05
上一篇:数据结构之双链表(超详解)
下一篇:数据结构之顺序表(超详解)
推荐阅读
留言与评论(共有 14 条评论) |
本站网友 海平面上升速度 | 26分钟前 发表 |
(即链表在物理结构上不一定连续 | |
本站网友 天津金海马 | 29分钟前 发表 |
字符型等等 typedef struct Slistode { DataType data;//节点数据 struct Slistode* next;//指向下一个节点的指针 }SLTode; //链表的打印 void SLTPrint(SLTode* phead); //创建节点 SLTode* SLTBuyode(DataType x); //尾插 void SLTPushBack(SLTode** pphead | |
本站网友 油压 | 17分钟前 发表 |
头插不需要考虑链表是否为空的情况 | |
本站网友 废物管理 | 28分钟前 发表 |
DataType x); //在指定位置之前插入数据 void SLTInsert(SLTode** pphead | |
本站网友 运城二手房信息 | 9分钟前 发表 |
DataType x); //在指定位置之前插入数据 void SLTInsert(SLTode** pphead | |
本站网友 滔滔千里心 | 26分钟前 发表 |
数据 指向下一个节点的指针 typedef int DataType;//可能存储整形 | |
本站网友 鑫海汇 | 28分钟前 发表 |
. 尾插 | |
本站网友 519008 | 11分钟前 发表 |
上图指针变量 plist保存的是第一个结点的地址 | |
本站网友 德信早城二手房 | 18分钟前 发表 |
DataType x); //尾删 void SLTPopBack(SLTode** pphead); //头删 void SLTPopFront(SLTode** pphead); //查 SLTode* SLTFind(SLTode* phead | |
本站网友 华东交通大学软件学院 | 18分钟前 发表 |
我们需要通过指针变量来保存下⼀个结点位置才能从当前结点到下一个结点 | |
本站网友 新东方视频 | 17分钟前 发表 |
(即链表在物理结构上不一定连续 | |
本站网友 十大促进伤口愈合的食物 | 13分钟前 发表 |
DataType x); //在指定位置之后插入数据 void SLTInsertAfter(SLTode* pos | |
本站网友 一个顶俩 | 27分钟前 发表 |
数据结构之单链表(超详解) 1. 单链表1.1 概念 |