IT评测·应用市场-qidao123.com
标题:
次序表与链表·续
[打印本页]
作者:
络腮胡菲菲
时间:
2025-3-8 11:10
标题:
次序表与链表·续
引言
本文承接上文(次序表与链表-CSDN博客),开始对链表的要点提炼。前文提到次序表得当需要
频仍随机访问
且数据量固定的场景,而链表得当需要
频仍插入和删除
且数据量动态厘革的场景。链表的引入弥补了次序表在动态性和操纵服从上的不敷,是线性表的告急实现方式之一。
链表
概念
链表是一种
物理存储结构上非连续
、非次序的存储结构,数据元素的
逻辑次序
是通过链表 中的
指针链接
实现的 。
链表结构 容易发现链表结构在逻辑上连续,但物理上不一定连续,一样平常链表的节点从堆上申请的,每次申请的空间是否连续是不确定的。
分类
链表的分类可以根据以下维度进行:
单向或双向
:决定节点的指针数量和遍历方向。
带头或不带头
:决定是否有额外的头节点简化操纵。
循环或不循环
:决定链表是否形成环。
通过组合这些维度,可以设计出得当不同场景的链表结构。例如:
带头单向循环链表
:得当实现队列。
带头双向循环链表
:得当需要双向遍历且操纵简化的场景。
而我们常遇到的主要是不带头单向非循环链表和带头双向循环链表(以下图例分别对应这两种链表)
不带头单向非循环链表
带头双向循环链表
实现
无头单向非循环链表的简单实现
//"slist.h"
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
if (*pplist == NULL) {
*pplist = newnode;
}
else
{
SListNode* tail = *pplist;
while (tail->next!=NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
newnode->next = *pplist;
*pplist = newnode;
}
// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
//一个节点
if ((*pplist)->next == NULL) {
free(*pplist);
*pplist = NULL;
}
//多个节点
SListNode* tail = *pplist;
while (tail->next->next!=NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
void SListPopFront(SListNode** pplist) {
// 防御性检查:拦截非法输入
if (pplist == NULL) {
fprintf(stderr, "Error: Invalid pointer in SListPopFront\n");
return;
}
// 业务逻辑检查:空链表直接返回
if (*pplist == NULL) {
return;
}
SListNode* tmp = *pplist;
*pplist = tmp->next;
free(tmp);
}
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
SListNode* cur = plist;
while (cur) {
if (cur->data == x) {
return cur;
}
cur = cur->next;
}
return NULL;
}
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
// 因为没有前置指针
// 若要在 pos 之前插入,必须从头节点开始遍历链表找到 pos 的前驱节点,时间复杂度为 O(n)
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
if (pos == NULL) return;
SListNode* newNode = BuySListNode(x);
newNode->next = pos->next;
pos->next = newNode;
}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
//删除 pos 节点需要知道其前驱节点,而单链表无法直接获取前驱节点
// 必须从头遍历链表,时间复杂度为O(n),删除 pos 之后的节点只需修改 pos->next,时间复杂度为O(1)。
void SListEraseAfter(SListNode* pos)
{
if (pos == NULL || pos->next == NULL) return;
SListNode* tmp = pos->next;
pos->next = tmp->next;
free(tmp);
}
// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
assert(*pphead);
if (*pphead == pos) SListPushFront(pphead,x);
else
{
SListNode* prev = *pphead;
while (prev->next!=pos)
{
prev = prev->next;
}
SListNode* newnode=BuySListNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
// 删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos)
{
assert(pphead);
assert(*pphead);
assert(pos);
if (*pphead == pos)
{
// 头删
SListPopFront(pphead);
}
else
{
SListNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
void SLTDestroy(SListNode** pphead)
{
assert(pphead);
SListNode* cur = *pphead;
while (cur) {
SListNode* tmp = cur;
cur = cur->next;
free(tmp);
}
*pphead = NULL;
}
复制代码
关键点说明
二级指针的利用
:
修改头指针时(如插入/删除头节点),需通过二级指针 pplist 修改一级指针 *pplist。
示例:SListPushFront 和 SListPopFront 直接修改头指针。
边界条件处理惩罚
:
空链表、单节点链表、尾节点/头节点操纵需特殊处理惩罚。
例如 SListPopBack 中需处理惩罚链表只有一个节点的环境。
时间复杂度
:
头插/头删:O(1)/O(1)
尾插/尾删:O(n)/O(n)
插入/删除指定位置:平均 O(n)/O(n)(需遍历找到位置)
内存管理
:
每次 malloc 后需检查内存分配是否成功。
删除节点后需及时 free 防止内存泄漏。
若需要频仍在恣意位置前插入或删除,最好利用
双向链表
,它可以通过前驱指针直接操纵,时间复杂度为 O(1)/O(1)。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4