爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      【数据结构】单链表(长期维护)

      首页 知识中心 软件开发 文章详情页

      【数据结构】单链表(长期维护)

      2025-02-12 09:27:53 阅读次数:13

      LINK,思路,接口,节点,链表

      下面是本项目的大体思路梳理:

      【数据结构】单链表(长期维护)

      一、实现单链表

      全部接口一览:

      【数据结构】单链表(长期维护)

      void SLTPrint(SLTNode* phead);//打印
      void SLTPushBack(SLTNode** pphead,SLTDateType x);//尾插
      void SLTPushiFront(SLTNode** pphead, SLTDateType x);//头插
      void SLTPopBack(SLTNode** pphead);//尾删
      void SLTPopFront(SLTNode** pphead);//头删
      void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDateType x);//任意位置之前插入
      SLTNode* SLTFind(SLTNode** pphead, SLTDateType x);//查找接口
      void SLTInsertAfter(SLTNode* pos, SLTDateType x);//任意位置之后插入
      void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos指向的节点
      void SLTEraseAfter(SLTNode* pos);//删除pos指向之后的节点
      void SLTDestroy(SLTNode** pphead);//销毁链表接口
      

      1.创建链表的结构体

      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      //定义单链表结构体
      #define SLTDateType int
      typedef struct SListNode
      {
      	SLTDateType date;//每个节点的数据
      	struct SListNode* next;//每个节点存储下一个节点的地址
      }SLTNode;
      

      2.打印链表的接口实现

      首先制造一些节点并进行相连操作
      【数据结构】单链表(长期维护)
      打印函数实现的思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      void SLTPrint(SLTNode* phead)
      {
      	//定义一个新的指针
      	SLTNode* pcur = phead;
      
      	//循环打印即可,什么时候停止?pcur不指向空便不停止
      	while (pcur)
      	{
      		//打印数据
      		printf("%d->", pcur->date);
      		//更新指针
      		pcur = pcur->next;
      	}
      
      	//为了完善,我给最后也加一个NULL
      	printf("NULL\n");
      }
      

      3.尾插接口实现

      思路:定义一个新指针,找到原链表的尾节点,找到了接上即可。
      【数据结构】单链表(长期维护)
      这里为什么要分类进行讨论?这由思路决定的,因为如果是空链表的情况下,ptail->next根本就是错误的,因为不存在。
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)
      新空间开辟接口:
      【数据结构】单链表(长期维护)

      void SLTPushBack(SLTNode** pphead, SLTDateType x)
      {
      	assert(pphead);
      
      	//申请一块新的空间
      	SLTNode* newnode = SLTBuyNode(x);
      	//分两种情况
      	//链表为空
      	if (*pphead == NULL)
      	{
      		*pphead = newnode;
      	}
      	else//链表不为空
      	{
      		SLTNode* ptail = *pphead;//用于找到链表的尾节点
      		while (ptail->next)
      		{
      			ptail = ptail->next;
      		}//找到尾节点
      		ptail->next = newnode;//给他接上
      	}
      }
      
      
      SLTNode* SLTBuyNode(SLTDateType x)
      {
      	//申请一块新的空间
      	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
      	//放内容
      	newnode->date = x;
      	newnode->next = NULL;
      	//返回地址
      	return newnode;
      }
      

      4.头插接口实现

      思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)
      尾插需要分情况讨论而头插怎么不需要呢?还是思路决定的,这个思路没有用到ptail->next所以就不需要考虑空链表的情况

      void SLTPushiFront(SLTNode** pphead, SLTDateType x)
      {
      	assert(pphead);
      
      	//申请一块新的空间
      	SLTNode* newnode = SLTBuyNode(x);
      	//把原来第一个结点的地址交给新节点的next
      	newnode->next = *pphead;
      	*pphead = newnode;//把头部指针更新一下
      }
      

      5.尾删接口实现

      思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)
      这里为什么要分只有一个节点和多个节点的不同情况?因为涉及到prev问题如果是只有一个节点,ptail指向第一个节点,那prev指针指向哪里?所以要对只有一个节点的链表单独进行处理。

      void SLTPopBack(SLTNode** pphead)
      {
      	//检验
      	assert(pphead);//原本的指针不能是空
      	assert(*pphead);//传过来的不能是空指针给我删除啊
      
      	//删除
      	//这里分两种情况
      	//1.只有一个节点的情况
      	if (*pphead == NULL)
      	{
      		free(*pphead);
      		*pphead = NULL;
      		return;
      	}
      	else//多个节点的情况
      	{
      		//需要找到最后一个节点和倒数第二个节点
      		//最后一个节点是为了释放空间
      		//倒数第二个节点是为了把他的next部分置为空
      		SLTNode* ptail = *pphead;
      		SLTNode* prev = *pphead;
      		while (ptail->next)
      		{
      			prev = ptail;
      			ptail = ptail->next;
      		}
      
      		//第二个节点next置为空
      		prev->next = NULL;
      		//销毁第一个节点
      		free(ptail);
      		ptail = NULL;
      	}
      }
      

      6.头删接口的实现

      思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      void SLTPopFront(SLTNode** pphead)
      {
      	//检验
      	assert(pphead);//检验你别给我传个空
      	assert(*pphead);//检验链表不为空,空链表删除什么?
      
      	//开始准备删除
      	SLTNode* next = (*pphead)->next;//记录一下要接上的地址
      	free(*pphead);//释放第一个节点
      	*pphead = next;
      }
      

      7.查找接口实现

      查找接口是做什么的呢?找一个节点的地址的。
      思路实现:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      SLTNode* SLTFind(SLTNode** pphead, SLTDateType x)
      {
      	//检查
      	assert(pphead);//别传空指针进来
      	//这里可以传空链表吗?可以!顶多找不到给你返回一个NULL嘛
      
      	//遍历链表
      	SLTNode* pcur = *pphead;
      	while (pcur)//当pcur找到NULL时候就会停止
      	{
      		if (pcur->date == x)
      		{
      			return pcur;//满足条件,返回该节点的地址
      		}
      		pcur = pcur->next;//更新指针
      	}
      	//如果什么都没有找到的话,是不是会不太合适\
      	// 所以我们规定如果没有找到,返回NULL地址
      
      	return NULL;
      }
      
      

      8.在指定位置之前插入数据

      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
      {
      	//检验
      	assert(pphead);//传入地址不得为空
      	assert(pos);//pos不得为空
      	assert(*pphead);//要加上链表不得为空,\
      	这是因为pos是链表的一个节点的地址,如 \
          果链表不存在,那么pos也会不存在
      
      	//这里要分情况进行处理
      	//1.pos刚好是头节点
      	if (pos == *pphead)
      	{
      		//直接调用头插
      		SLTPushiFront(pphead,x);
      		return;
      	}
      	else//2.如果pos不是头节点
      	{
      		SLTNode* prev = *pphead;
      		//让prev找到pos之前的节点的地址
      		while (prev->next != pos)
      		{
      			prev = prev->next;
      		}
      		
      		SLTNode* newnode = SLTBuyNode(x);//申请空间
      		prev->next = newnode;//把新空间链接到我们前一个节点
      		newnode->next = pos;//把新空间与pos指向的空间链接在一起
      	}
      }
      
      

      9.在指定位置之后插入数据的接口实现

      思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)
      思考:上面说的关联新节点的错误是如何引起的呢?
      答:因为新节点的后面的节点的地址表示是靠的pos->next

      void SLTInsertAfter(SLTNode* pos, SLTDateType x)//之后
      {
      	//检查
      	assert(pos);
      	
      	//申请空间
      	SLTNode* newnode = SLTBuyNode(x);
      
      	//关联新节点的错误写法,原因:pos值的改变
      	//pos->next = newnode;
      	//newnode->next = pos->next;
      
      	//关联新节点的正确写法:
      	//先接后面,再接前面
      	newnode->next = pos->next;
      	pos->next = newnode;
      
      }
      

      10.删除指定位置的节点

      思路:
      【数据结构】单链表(长期维护)

      【数据结构】单链表(长期维护)

      void SLTErase(SLTNode** pphead, SLTNode* pos)
      {
      	//检查
      	assert(pphead);//不得传空
      	assert(*pphead);//不得为空链表
      	assert(pos);
      
      	//pos刚好是头节点的情况,头删
      	if (*pphead == pos)
      	{
      		//头删
      		SLTPopFront(pphead);
      		return;
      	}
      	//如果不是头节点
      	else {
      		//找到pos之前的节点
      		SLTNode* prev = *pphead;
      		while (prev->next != pos)
      		{
      			prev = prev->next;
      		}
      		prev->next = pos->next;
      		free(pos);
      		pos = NULL;
      	}
      
      }
      

      11.删除指定位置之后的节点接口实现

      思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      void SLTEraseAfter(SLTNode* pos)
      {
      	//检查
      	assert(pos);//传过来的地址不可以为空
      	assert(pos->next);//传过来的地址的下一个地址不得为空
      
      	SLTNode* del = pos->next;//记录要删除的节点的地址
      	pos->next = pos->next->next;//更新pos中next的地址
      	free(del);//释放空间
      	del = NULL;//临时指针及时置为空
      }
      

      12.销毁链表接口

      思路:
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      void SLTDestroy(SLTNode** pphead)
      {
      	assert(pphead);//传过来的指针不得为空
      	assert(*pphead);//链表不得为空,空链表不用销毁
      
      	//创建遍历指针
      	SLTNode* pcur = *pphead;
      	//循环销毁
      	while (pcur)//啥时候停止?pcur指向NULL
      	{
      		SLTNode* next = pcur->next;
      		free(pcur);
      		pcur = next;
      	}
      	//最后把头指针也置为NULL
      	*pphead = NULL;
      }
      

      全部代码合集

      //SList.h
      #pragma once
      #include<stdlib.h>
      #include<stdio.h>
      #include<assert.h>
      
      //定义单链表结构体
      #define SLTDateType int
      typedef struct SListNode
      {
      	SLTDateType date;//每个节点的数据
      	struct SListNode* next;//每个节点存储下一个节点的地址
      }SLTNode;
      
      
      void SLTPrint(SLTNode* phead);//打印
      void SLTPushBack(SLTNode** pphead,SLTDateType x);//尾插
      void SLTPushiFront(SLTNode** pphead, SLTDateType x);//头插
      void SLTPopBack(SLTNode** pphead);//尾删
      void SLTPopFront(SLTNode** pphead);//头删
      void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDateType x);//任意位置之前插入
      SLTNode* SLTFind(SLTNode** pphead, SLTDateType x);//查找接口
      void SLTInsertAfter(SLTNode* pos, SLTDateType x);//任意位置之后插入
      void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos指向的节点
      void SLTEraseAfter(SLTNode* pos);//删除pos指向之后的节点
      void SLTDestroy(SLTNode** pphead);//销毁链表接口
      
      //SList.c
      #include"SList.h"
      
      SLTNode* SLTBuyNode(SLTDateType x)
      {
      	//申请一块新的空间
      	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
      	//放内容
      	newnode->date = x;
      	newnode->next = NULL;
      	//返回地址
      	return newnode;
      }
      
      SLTNode* SLTFind(SLTNode** pphead, SLTDateType x)
      {
      	//检查
      	assert(pphead);//别传空指针进来
      	//这里可以传空链表吗?可以!顶多找不到给你返回一个NULL嘛
      
      	//遍历链表
      	SLTNode* pcur = *pphead;
      	while (pcur)//当pcur找到NULL时候就会停止
      	{
      		if (pcur->date == x)
      		{
      			return pcur;//满足条件,返回该节点的地址
      		}
      		pcur = pcur->next;//更新指针
      	}
      	//如果什么都没有找到的话,是不是会不太合适\
      	// 所以我们规定如果没有找到,返回NULL地址
      
      	return NULL;
      }
      
      void SLTPrint(SLTNode* phead)
      {
      	//定义一个新的指针
      	SLTNode* pcur = phead;
      
      	//循环打印即可,什么时候停止?pcur不指向空便不停止
      	while (pcur)
      	{
      		//打印数据
      		printf("%d->", pcur->date);
      		//更新指针
      		pcur = pcur->next;
      	}
      
      	//为了完善,我给最后也加一个NULL
      	printf("NULL\n");
      }
      
      void SLTPushBack(SLTNode** pphead, SLTDateType x)
      {
      	assert(pphead);
      
      	//申请一块新的空间
      	SLTNode* newnode = SLTBuyNode(x);
      	//分两种情况
      	//链表为空
      	if (*pphead == NULL)
      	{
      		*pphead = newnode;
      	}
      	else//链表不为空
      	{
      		SLTNode* ptail = *pphead;//用于找到链表的尾节点
      		while (ptail->next)
      		{
      			ptail = ptail->next;
      		}//找到尾节点
      		ptail->next = newnode;//给他接上
      	}
      }
      
      void SLTPushiFront(SLTNode** pphead, SLTDateType x)
      {
      	assert(pphead);
      
      	//申请一块新的空间
      	SLTNode* newnode = SLTBuyNode(x);
      	//把原来第一个结点的地址交给新节点的next
      	newnode->next = *pphead;
      	*pphead = newnode;//把头部指针更新一下
      }
      
      void SLTPopBack(SLTNode** pphead)
      {
      	//检验
      	assert(pphead);//原本的指针不能是空
      	assert(*pphead);//传过来的不能是空指针给我删除啊
      
      	//删除
      	//这里分两种情况
      	//1.只有一个节点的情况
      	if (*pphead == NULL)
      	{
      		free(*pphead);
      		*pphead = NULL;
      		return;
      	}
      	else//多个节点的情况
      	{
      		//需要找到最后一个节点和倒数第二个节点
      		//最后一个节点是为了释放空间
      		//倒数第二个节点是为了把他的next部分置为空
      		SLTNode* ptail = *pphead;
      		SLTNode* prev = *pphead;
      		while (ptail->next)
      		{
      			prev = ptail;
      			ptail = ptail->next;
      		}
      
      		//第二个节点next置为空
      		prev->next = NULL;
      		//销毁第一个节点
      		free(ptail);
      		ptail = NULL;
      	}
      }
      
      void SLTPopFront(SLTNode** pphead)
      {
      	//检验
      	assert(pphead);//检验你别给我传个空
      	assert(*pphead);//检验链表不为空,空链表删除什么?
      
      	//开始准备删除
      	SLTNode* next = (*pphead)->next;//记录一下要接上的地址
      	free(*pphead);//释放第一个节点
      	*pphead = next;
      }
      
      
      void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
      {
      	//检验
      	assert(pphead);//传入地址不得为空
      	assert(pos);//pos不得为空
      	assert(*pphead);//要加上链表不得为空,
      	//这是因为pos是链表的一个节点的地址,如 
          //果链表不存在,那么pos也会不存在
      
      	//这里要分情况进行处理
      	//1.pos刚好是头节点
      	if (pos == *pphead)
      	{
      		//直接调用头插
      		SLTPushiFront(pphead,x);
      		return;
      	}
      	else//2.如果pos不是头节点
      	{
      		SLTNode* prev = *pphead;
      		//让prev找到pos之前的节点的地址
      		while (prev->next != pos)
      		{
      			prev = prev->next;
      		}
      		
      		SLTNode* newnode = SLTBuyNode(x);//申请空间
      		prev->next = newnode;//把新空间链接到我们前一个节点
      		newnode->next = pos;//把新空间与pos指向的空间链接在一起
      	}
      }
      
      
      void SLTInsertAfter(SLTNode* pos, SLTDateType x)//之后
      {
      	//检查
      	assert(pos);
      	
      	//申请空间
      	SLTNode* newnode = SLTBuyNode(x);
      
      	//关联新节点的错误写法,原因:pos值的改变
      	//pos->next = newnode;
      	//newnode->next = pos->next;
      
      	//关联新节点的正确写法:
      	//先接后面,再接前面
      	newnode->next = pos->next;
      	pos->next = newnode;
      
      }
      
      void SLTErase(SLTNode** pphead, SLTNode* pos)
      {
      	//检查
      	assert(pphead);//不得传空
      	assert(*pphead);//不得为空链表
      	assert(pos);
      
      	//pos刚好是头节点的情况,头删
      	if (*pphead == pos)
      	{
      		//头删
      		SLTPopFront(pphead);
      		return;
      	}
      	//如果不是头节点
      	else {
      		//找到pos之前的节点
      		SLTNode* prev = *pphead;
      		while (prev->next != pos)
      		{
      			prev = prev->next;
      		}
      		prev->next = pos->next;
      		free(pos);
      		pos = NULL;
      	}
      
      }
      
      
      void SLTEraseAfter(SLTNode* pos)
      {
      	//检查
      	assert(pos);//传过来的地址不可以为空
      	assert(pos->next);//传过来的地址的下一个地址不得为空
      
      	SLTNode* del = pos->next;//记录要删除的节点的地址
      	pos->next = pos->next->next;//更新pos中next的地址
      	free(del);//释放空间
      	del = NULL;//临时指针及时置为空
      }
      
      void SLTDestroy(SLTNode** pphead)
      {
      	assert(pphead);//传过来的指针不得为空
      	assert(*pphead);//链表不得为空,空链表不用销毁
      
      	//创建遍历指针
      	SLTNode* pcur = *pphead;
      	//循环销毁
      	while (pcur)//啥时候停止?pcur指向NULL
      	{
      		SLTNode* next = pcur->next;
      		free(pcur);
      		pcur = next;
      	}
      	//最后把头指针也置为NULL
      	*pphead = NULL;
      }
      
      //test.c
      #define _CRT_SECURE_NO_WARNINGS 1
      #include"SList.h"
      
      void test1()
      {
      	//头指针
      	SLTNode* phead = NULL;
      	//造一点结点
      	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
      	node1->date = 1;
      	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
      	node2->date = 2;
      	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
      	node3->date = 3;
      	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
      	node4->date = 4;
      	SLTNode* node5 = (SLTNode*)malloc(sizeof(SLTNode));
      	node5->date = 5;
      
      	//链接这些节点
      	phead = node1;
      	node1->next = node2;
      	node2->next = node3;
      	node3->next = node4;
      	node4->next = node5;
      	node5->next = NULL;
      
      	//调用一下打印函数
      	SLTPrint(phead);
      }
      
      void test2()
      {
      	SLTNode* phead = NULL;
      
      	SLTPushBack(&phead,6);
      	SLTPrint(phead);
      
      	SLTPushiFront(&phead,0);
      	SLTPushiFront(&phead,1);
      	SLTPushiFront(&phead,2);
      	SLTPushiFront(&phead,3);
      	SLTPushiFront(&phead,4);
      	SLTPushiFront(&phead,5);
      	SLTPrint(phead);//5->4->3->2->1->0->6->NULL
      
      	SLTPopBack(&phead);
      	SLTPrint(phead);//5->4->3->2->1->0->NULL
      	SLTPopFront(&phead);
      	SLTPopFront(&phead);
      	SLTPopFront(&phead);
      	SLTPopFront(&phead);
      	SLTPrint(phead);//1->0->NULL
      	
      	SLTNode* find = SLTFind(&phead,1);
      	SLTInsert(&phead, find, 2);
      	SLTPrint(phead);//2->1->0->NULL
      	SLTInsertAfter(find, 8);
      	SLTPrint(phead);//2->1->8->0->NULL
      	
      	SLTEraseAfter(find);
      	SLTPrint(phead);//2->8->0->NULL
      
      	SLTDestroy(&phead);
      	SLTPrint(phead);//NULL
      
      }
      
      int main()
      {
      	//测试我的打印函数
      	//test1();
      	//测试我的插入与删除函数
      	test2();
      	return 0;
      }
      

      二、相关练习题

      1.中间链表

      题目链接:LINK
      详细解答:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      struct ListNode* middleNode(struct ListNode* head) {
          //思路1:暴力求解法
          /*int length = 0;
          struct ListNode* pcur = head;
          while(pcur)
          {
              length++;
              pcur = pcur->next;
          }
      
          length/=2;
          pcur = head;
          while(length--)
          {
              pcur = pcur->next;
          }
      
          return pcur;
          */
          //思路2:双指针法
          struct ListNode* slow = head;
          struct ListNode* fast = head;
          
          while(fast && fast->next)
          {
              slow = slow->next;
              fast = fast->next->next;
          }
      
          return slow;
      }
      

      2.删除链表中等于给定值 val 的所有结点

      题目链接:LINK
      多种解题思路:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
       struct ListNode* removeElements(struct ListNode* head, int val){
          
          //处理*head == val 的情况,使*head!=val
          while (head && head->val == val) 
          {
              head = head->next;
          }
          //如果是空链表,返回
          if(head == NULL)
          {
              return NULL;
          }
          
          //走到这里,head不是val并且该链表不为空
          struct ListNode* cur = head->next;//如果head为空链表这样写不合法
          struct ListNode* pre = head;
      
          while (cur != NULL) {
              if (cur->val == val) 
              {
              //跳跃
              pre->next = cur->next;
              //free
              struct ListNode* temp = cur;
              } 
              else 
              {
                  //下一个跟进cur
                  pre = cur;
              }
              //cur不断向前走
              cur = cur->next;
          }
      
          return head;
      }
      
      
      
      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
       struct ListNode* removeElements(struct ListNode* head, int val){
          
          //定义新链表的头尾指针
          struct ListNode* newHead = NULL;
          struct ListNode* newTail = NULL;
      
          //
          struct ListNode* pcur = head;
          while(pcur)
          {
              //不是val,尾插到新链表
              if(pcur->val!=val)
              {
                  if(newHead == NULL)
                  {
                      //链表为空
                      newHead = newTail = pcur;
                  }
                  else//链表不为空
                  {
                      newTail->next = pcur;
                      newTail = newTail->next;//更新尾节点
                  }
              }
      
              //更新pcur指针
              pcur = pcur->next;
          }
      
          //加上null
              if(newTail)
              {
                  newTail->next = NULL;
              }
      
          //返回
              return newHead;
      }
      
      

      3.反转链表

      题目链接:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      
      struct ListNode* reverseList(struct ListNode* head) {
      
          //防止给我一个空的链表,如果说给我一个空链表,那么我们下面的n2->next会报错
          if(head == NULL) 
          return head;
          
          //指针初始化
          struct ListNode* n1 = NULL;
          struct ListNode* n2 = head;
          struct ListNode* n3 = n2->next;
           
          while(n2)
          {
              n2->next = n1;//改变指向
              n1 = n2;
              n2 = n3;
              if(n3)//如果n3不为空,那么让n3往下走一个
              n3 = n3->next;
          }
      
          return n1;
      }
      
      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      
      struct ListNode* reverseList(struct ListNode* head) {
          //头插的思路
      struct ListNode* newhead = NULL;
      struct ListNode* pcur = head;
      
      while(pcur)
      {
          struct ListNode* next = pcur->next;
          pcur->next = newhead;
          newhead = pcur;
          pcur = next;
      }
          
      return newhead;
      }
      

      4.分割链表

      题目链接:LINK
      【数据结构】单链表(长期维护)

      #include<stdio.h>
      #include<stdlib.h>
      /*
      struct ListNode {
          int val;
          struct ListNode *next;
          ListNode(int x) : val(x), next(NULL) {}
      };*/
      
      class Partition {
      public:
          ListNode* partition(ListNode* pHead, int x) {
              // write code here
              //申请哨兵位置
              struct ListNode* sentry1 = (struct ListNode*)malloc(sizeof(struct ListNode));
              struct ListNode* sentry2 = (struct ListNode*)malloc(sizeof(struct ListNode));
              //定义指针
              struct ListNode* newhead1,*newhead2,*newtail1,*newtail2;
              newhead1 = newtail1 = sentry1;
              newhead2 = newtail2 = sentry2;
              //按照条件分割
              struct ListNode* pcur = pHead;
              while(pcur)
              {
                  if(pcur->val<x)
                  {
                      newtail1->next = pcur;
                      newtail1 = newtail1->next;
                  }
                  else 
                  {
                      newtail2->next = pcur;
                      newtail2 = newtail2->next;
                  }
                  pcur = pcur->next;
              }
              //链接list1与list2
              
              newtail1->next = newhead2->next;
              newtail2->next = NULL;
      
              pHead = newhead1->next;
              free(newhead1);
              free(newhead2);
      
              return pHead;
          }
      };
      

      5.链表中倒数第K个结点

      题目链接:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      
      
      int kthToLast(struct ListNode* head, int k){
      struct ListNode* pcur = head;
      int count = 0;
      while(pcur)
      {
          count++;
          pcur = pcur->next;
      }
      
      count = count - k;
      pcur = head;
      while(count--)
      {
          pcur = pcur->next;
      }
      
      return pcur->val;
      }
      
      
      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      
      
      int kthToLast(struct ListNode* head, int k){
      struct ListNode* slow = head;
      struct ListNode* fast = head;
      while(k--)
      {
          fast = fast->next;
      }
      
      while(fast)
      {
          slow = slow->next;
          fast = fast->next;
      }
      
      return slow->val;
      }
      
      

      6.合并链表

      题目链接:LINK
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
          //考虑空链表的情况:
      
          //1.两个链表都是空的
          if(list1 == NULL && list2 == NULL)
          {
              return NULL;
          }
          //2.只有list1是空的
          if(list1 == NULL)
          {
              return list2;
          }
          //3.只有list2是空的
          if(list2 == NULL)
          {
              return list1;
          }
      
          //走到这里,就说明两个链表都不为空了。
          struct ListNode* head = NULL;
          struct ListNode* tail = NULL;
      
          //定义两个指针分别遍历两个链表
          struct ListNode* pcur1 = list1;
          struct ListNode* pcur2 = list2;
      
          while(pcur1 && pcur2)
          {
              if(pcur1->val < pcur2->val)
              {
                  if(head == NULL)
                  {
                      head = tail = pcur1;
                  }
                  else
                  {
                      tail->next = pcur1;
                      tail = pcur1;
                  }
                  pcur1 = pcur1->next;
              }
              else
              {
                  if(head == NULL)
                  {
                      head = tail = pcur2;
                  }
                  else
                  {
                      tail->next = pcur2;
                      tail = pcur2;
                  }
                  pcur2 = pcur2->next;
              }
          }
      
          //走到这里,会出现两种情况,要不剩下list1,要不剩下list2
          while(pcur1)
          {
              tail->next = pcur1;
              tail = pcur1;
              pcur1 = pcur1->next;
          }
          while(pcur2)
          {
              tail->next = pcur2;
              tail = pcur2;
              pcur2 = pcur2->next;
          }
      
          return head;
      }
      

      7.链表的回文结构

      题目链接:LINK
      详细解答:LINK
      【数据结构】单链表(长期维护)

      /*
      struct ListNode {
          int val;
          struct ListNode *next;
          ListNode(int x) : val(x), next(NULL) {}
      };*/
      
      
      
      //找到中间结点
      struct ListNode* middleNode(struct ListNode* head) {
          //思路2:快慢指针法
      
          struct ListNode* fast = head;
          struct ListNode* slow = head;
      
          while(fast && fast->next)//快指针走到头
          {
              slow = slow->next;
              fast = fast->next->next;
          }
      
          return slow;
      }
      
      
      struct ListNode* reverseList(struct ListNode* head)
      {
          //逆置链表为空
          if(head == nullptr) 
          return head;
      
          //不为空
          struct ListNode* n1 = nullptr;
          struct ListNode* n2 = head;
          struct ListNode* n3 = head->next;
      
          while(n2)
          {
              //逆置
              n2->next = n1;
              //移动n1、n2、n3指向下一个
              n1 = n2;
              n2 = n3;
              if(n3)//n3不为空
              {
                  n3 = n3->next;
              }
          }
      
          return n1;
      }
      
      class PalindromeList {
      public:
          bool chkPalindrome(ListNode* A) {
              // write code here
              //找到中间节点
              struct ListNode* pMidNode = middleNode(A);
              //逆置中间节点及其以后的节点
              struct ListNode* pNewMidNode = reverseList(pMidNode);
              //对比
              while(A&&pNewMidNode)
              {
                  if(pNewMidNode->val!=A->val)
                  {
                      return false;
                  }
                  //向后走
                  A = A->next;
                  pNewMidNode = pNewMidNode->next;
              }
      
              return true;
          }
      };
      

      8.查找相交结点

      题目链接:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
       #include<math.h>
      
      struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
          
          //判断是不是相交链表
          struct ListNode* pTailA = headA;
          struct ListNode* pTailB = headB;
          int skipA = 0;//统计A链表中结点的个数
          int skipB = 0;//统计B链表中结点的个数
      
          //统计结点个数
          while(pTailA->next)
          {
              pTailA=pTailA->next;
              skipA++;
          }
          skipA++;//统计少了一个,给他加上
      
           while(pTailB->next)
          {
              pTailB=pTailB->next;
              skipB++;
          }
          skipB++;
      
          //不是交点
          if(pTailA!=pTailB)
          {
              return NULL;
          }
      
          //如果是,那么证明他们一定是相交的了,所以我们要查找出他的交点
          
      
          int sub = abs(skipA-skipB); 
      
          struct ListNode* pmin = NULL;
          struct ListNode* pmax = NULL;
          
          if(skipA<skipB)
          {
              pmin = headA;
              pmax = headB;
          }
          else
          {
              pmin = headB;
              pmax = headA;
          }
          //让长的先走一些,让长短对齐
          while(sub--)
          {
              pmax = pmax->next;
          }
          //找交点
          while(pmin!=pmax)
          {
              pmin = pmin->next;
              pmax = pmax->next;
          }
          
          return pmax;
      }
      

      9.判断有环链表

      题目链接:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      bool hasCycle(struct ListNode *head) {
          struct ListNode* fast = head;
          struct ListNode* slow = head;
      
          while(fast&&fast->next)
          {
              slow=slow->next;
              fast = fast->next->next;
      
              if(fast == slow)
              {
                  return true;
              }
          }
          
          return false;
      }
      

      10.有环链表找入环结点

      题目链接:LINK
      【数据结构】单链表(长期维护)
      【数据结构】单链表(长期维护)

      /**
       * Definition for singly-linked list.
       * struct ListNode {
       *     int val;
       *     struct ListNode *next;
       * };
       */
      struct ListNode *detectCycle(struct ListNode *head) {
          struct ListNode* fast = head;
          struct ListNode* slow = head;
      
          while(fast&&fast->next)
          {
              slow=slow->next;
              fast = fast->next->next;
      
              if(fast == slow)
              {
                  struct ListNode * meet = slow;
                  struct ListNode * headx = head;
                  while(meet!=headx)
                  {
                      meet = meet->next;
                      headx = headx->next;
                  }
                  return meet;
              }
          }
          return NULL;
      }
      
      struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
      {
          //首先统计每个链表结点的个数
          int count1 = 0;
          int count2 = 0;
          struct ListNode *pcur1 = headA,*pcur2 = headB;
          while(pcur1)
          {
              count1++;
              pcur1 = pcur1->next;
          }
          while(pcur2)
          {
              count2++;
              pcur2 = pcur2->next;
          }
      
          struct ListNode *maxhead = headA;
          struct ListNode *minhead = headB;
          if(count1 < count2)
          {
              maxhead = headB;
              minhead = headA;
          }
      
          int sub = count1-count2;
          if(sub<0)
          {
              sub = 0-sub;
          }
      
          while(sub--)
          {
              maxhead = maxhead->next;
          }
      
          while(minhead!=maxhead)
          {
              minhead = minhead->next;
              maxhead = maxhead->next;
          }
      
          return maxhead;
      }
      
      struct ListNode *detectCycle(struct ListNode *head) {
         //方法二:转换题目:相交链表
         struct ListNode* slow = head,*fast = head;
         while(fast&&fast->next)
         {
          slow = slow->next;
          fast = fast->next->next;
          if(slow == fast)
          {
              struct ListNode* head1 = slow->next;
              struct ListNode* head2 = head;
              slow->next = NULL;
              struct ListNode* meet = getIntersectionNode(head1,head2);
              return meet;
          }
         }
         return NULL;
      }
      

      11.随机链表的复制

      题目链接:LINK
      【数据结构】单链表(长期维护)

      /**
       * Definition for a Node.
       * struct Node {
       *     int val;
       *     struct Node *next;
       *     struct Node *random;
       * };
       */
      
      struct Node* copyRandomList(struct Node* head) {
          if(head==NULL)
          {
              return NULL;
          }
      
      	struct Node* pcur = head;
          //插入一些复制结点
          while(pcur)
          {
              struct Node* pushback = (struct Node*)malloc(sizeof(struct Node));
              pushback->val = pcur->val;
      
              pushback->next = pcur->next;
              pcur->next = pushback;
      
              pcur = pcur->next->next;//调整pcur
          }
          //控制拷贝结点的random
          pcur = head;
          while(pcur)
          {
              //如果原链表的random指向空,那我们新链表也要指向空
              if(pcur->random == NULL)
              {
                  pcur->next->random = NULL;
                  pcur = pcur->next->next;
                  continue;
              }
      
              pcur->next->random = pcur->random->next;
              pcur = pcur->next->next;
          }
      
          //把拷贝结点放下来
          pcur = head;
          struct Node* pcurx = head->next;
          struct Node* returnpcurx = pcurx; 
      
          while(pcur)
          {
              pcur->next = pcur->next->next;
              pcur = pcur->next;
      
              //最后一个节点
              if(pcurx->next == NULL)
              {
                  pcurx->next = NULL;
                  break;
              }
              pcurx->next = pcurx->next->next;
              pcurx = pcurx->next;
          }
      
          //返回
          return returnpcurx;
      }
      

      EOF

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/2302_79031646/article/details/136151059,作者:睡觉待开机,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:【C项目】顺序表

      下一篇:【刷题记录】相交链表

      相关文章

      2025-05-19 09:04:44

      spark控制台没显示其他机器

      spark控制台没显示其他机器

      2025-05-19 09:04:44
      Spark , 节点 , 集群
      2025-05-19 09:04:14

      二叉树经典OJ练习

      二叉树经典OJ练习

      2025-05-19 09:04:14
      root , 二叉树 , 子树 , 节点 , 遍历
      2025-05-19 09:04:14

      复杂度的OJ练习

      复杂度的OJ练习

      2025-05-19 09:04:14
      代码 , 复杂度 , 思路 , 数组 , 算法
      2025-05-19 09:04:14

      【牛客网+LeetCode】链表 OJ强训题——高效解法

      【牛客网+LeetCode】链表 OJ强训题——高效解法

      2025-05-19 09:04:14
      数据结构 , 链表
      2025-05-16 09:15:10

      【C/C++算法】蓝桥杯之递归算法(如何编写想出递归写法)

      【C/C++算法】蓝桥杯之递归算法(如何编写想出递归写法)

      2025-05-16 09:15:10
      结点 , 递归 , 遍历 , 链表 , 题目
      2025-05-14 10:33:25

      超级好用的C++实用库之网络

      在网络相关的项目中,我们经常需要去获取和设置设备的IP地址、子网掩码、网关地址、MAC地址等信息。这些信息一般与操作系统相关,在Windows系统和Linux系统上调用的接口是不一样的。

      2025-05-14 10:33:25
      Linux , 参数 , 地址 , 接口 , 网卡 , 返回值
      2025-05-14 10:03:13

      数据结构-队列

      队列是仅限在一端进行插入,另一端进行删除的线性表。

      2025-05-14 10:03:13
      元素 , 入队 , 出队 , 链表 , 队列
      2025-05-14 10:03:13

      【MySQL】-数据库优化(索引)

      索引(index)是帮助数据库高效获取数据的数据结构

      2025-05-14 10:03:13
      index , Tree , 二叉 , 搜索 , 数据 , 索引 , 节点
      2025-05-14 10:02:48

      MongoDB常用管理命令(1)

      MongoDB常用管理命令(1)

      2025-05-14 10:02:48
      会话 , 命令 , 操作 , 节点
      2025-05-14 09:51:15

      java实现管线拓扑关系连通性分析

      管线拓扑关系的连通性分析通常涉及图论(Graph Theory)中的概念,特别是无向图(Undirected Graph)的遍历算法,如深度优先搜索(DFS, Depth-First Search)或广度优先搜索(BFS, Breadth-First Search)。

      2025-05-14 09:51:15
      BFS , DFS , 复杂度 , 搜索 , 节点 , 访问 , 遍历
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5245602

      查看更多

      最新文章

      复杂度的OJ练习

      2025-05-19 09:04:14

      【C/C++算法】蓝桥杯之递归算法(如何编写想出递归写法)

      2025-05-16 09:15:10

      超级好用的C++实用库之网络

      2025-05-14 10:33:25

      数据结构-队列

      2025-05-14 10:03:13

      JAVA 两个类同时实现同一个接口

      2025-05-14 09:51:15

      二叉搜索树中第K小的元素

      2025-05-13 09:50:17

      查看更多

      热门文章

      JAVA__接口的作用

      2023-04-18 14:14:13

      什么是api接口

      2023-03-22 09:03:21

      kotlin匿名内部类与接口实现

      2023-04-18 14:15:13

      Python|二进制链表转整数

      2023-02-27 10:24:46

      Go 语言入门很简单 -- 13. Go 接口 #私藏项目实操分享#

      2023-04-21 03:11:48

      SpringBoot写的后端API接口如何写得更优雅

      2023-06-15 06:37:47

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      拿捏链表(七)—— 链表的回文结构

      AOP的三种实现方式

      C语言刷题(二)

      springboot系列教程(二十五):springboot整合ElasticSearch,实现高性能搜索引擎

      Webapp答题之JavaScript篇

      数据结构---Java编码实现栈、队列、链表的常规功能

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号