当前位置: 首页 > news >正文

day19 链表

定义

链式存储的线性表

头文件相关定义 

typedef int datatype;//定义数据域类型
typedef struct Node
{union{int len;  //头结点数据域datatype data; //普通节点数据域};struct Node *next;   //节点指针域
}Node,*Node_ptr;

链表的函数 


创建单向链表

Node_ptr linklist_create();

函数功能:从堆区空间申请一个头结点并初始化并检查链表是否创建成功

参数:void

返回值:成功返回头结点地址失败返回NULL

 主要代码

Node_ptr l=(Node_ptr)malloc(sizeof(Node));
if(l==NULL)
{printf("创建链表失败\n");return NULL;		
}
//头结点初始化
l->len=0;//初始化长度为0
l->next=NULL;//初始化指针为空,防止野指针

链表判空操作

int link_empty(Node_ptr );

函数功能:判断链表是否为空

参数:链表头结点地址

返回值:为空返回1,否则返回0

 主要代码

//通过判断头结点的后继节点指针是否为空
return l->next==NULL; 

创建节点

Node_ptr Node_apply(datatype );

函数功能:从堆区申请一个新节点并判断是否申请成功,并初始化数据域

参数:节点数据域的值

返回值:成功返回节点地址,失败返回NULL

 主要代码

//堆区申请空间
Node_ptr p=(Node_ptr)malloc(sizeof(Node));
if(p==NULL)
{printf("节点空间申请失败\n");return NULL;
}
printf("节点申请成功\n");
p->data=e; //初始化数据域
p->next=NULL; //初始化指针为空
return p; //封装好的节点地址

单向链表头插

int link_insert_head(Node_ptr ,datatype );

函数功能:通过创建节点函数申请节点,并在链表头部插入新节点

参数:链表头结点地址、待插入数据

返回值:成功返回0,失败返回-1

//创建节点
//pa指针接收节点的地址
Node_ptr pa=Node_apply(e);
if(pa==NULL)
{printf("插入失败\n");return -1;
}
//头插逻辑
pa->next=L->next;//先继承头节点的指向
L->next=pa;  //再将头节点指针指向插入的节点
//长度自增
L->len++;

单向链表按位置查找

Node_ptr link_find_post(Node_ptr ,int );

函数功能:先判断位置是否合理,根据位置查找节点地址

参数:链表头结点地址、位置索引(从0开始)

返回值:成功返回节点地址,失败返回NULL

主要代码 

//判断逻辑
if(L==NULL||post<0||post>L->len)
{printf("查找失败\n");return NULL;
}
//查找逻辑
Node_ptr q=L; //定义一个遍历指针
for(int i=0;i<post;i++) //先移动再自加,所有不需要等于post
{q=q->next;//指向下一个节点
}
//返回节点
return q;

链表遍历

void show(Node_ptr );

函数功能:先判断是否为空,再打印链表中所有节点的数据

参数:链表头结点地址

返回值:void

 主要代码

//判断逻辑
if(link_empty(L))
{printf("遍历失败\n");
}
Node_ptr q=L->next; //遍历指针指向第一个节点
while(q)  //如果遍历为空,结束遍历
{printf("%-4d",q->data);//遍历数据q=q->next;//指向下一个节点
}

链表任意位置插入

int link_insert_post(Node_ptr ,int ,datatype);

函数功能:先判断位置是否合理,再在指定位置插入新节点

参数:链表头结点地址、位置索引、待插入数据

返回值:成功返回0,失败返回-1 

//创建节点
Node_ptr p=Node_apply(e);
if(p==NULL)
{printf("插入失败2\n");return -1;
}
//调用函数找到post-1的地址,用q接收
Node_ptr q=link_find_post(L,post-1);
//利用头插
p->next=q->next; //插入节点继承post-1节点的指针指向
q->next=p;    //psost-1节点指向插入节点
//长度自增
L->len++;

链表头删

int link_delete_head(Node_ptr );

函数功能:判断是否为空,删除链表首节点非头结点

参数:链表头结点地址

返回值:成功返回0,失败返回-1

//p记录节点地址
Node_ptr p=L->next;
//删除逻辑,头节点指向下一个节点
L->next=p->next;
//释放节点
free(p);
p=NULL;//防止野指针
//长度自减
L->len--;

任意位置删除

int link_delete_post(Node_ptr ,int );

函数功能:删除指定位置的节点

参数:链表头结点地址、位置索引

返回值:成功返回0,失败返回-1

//遍历到post前驱节点,p接收post-1地址
Node_ptr p=link_find_post(L,post-1);
//删除逻辑
//本质是p->next=(p->next)->next 
Node_ptr q=p->next; 
p->next=q->next;  //q被孤立
//释放节点,置空
free(q);
q=NULL;
//长度自减
L->len--;

按值查找位置

int link_find_value(Node_ptr ,datatype );

函数功能:查找数据值首次出现的位置

参数:链表头结点地址、待查找数据

返回值:成功返回位置索引(从1开始),失败返回-1

//查找逻辑
Node_ptr p=L->next; //p指向第一个节点
for(int i=1;i<=L->len;i++) //遍历查找
{	if(p->data==e)return i;p=p->next; //不匹配p往后移动
}
return -1;

按位置修改

int link_updata_post(Node_ptr ,int ,datatype);

函数功能:修改指定位置节点的数据

参数:链表头结点地址、位置索引、新数据

返回值:成功返回0,失败返回-1

//查找逻辑,用p接收post地址
Node_ptr p=link_find_post(L,post);
//修改逻辑
p->data=e;

按值修改

int link_updata_value(Node_ptr,datatype,datatype);

函数功能:修改链表中第一个匹配的节点数据

参数:链表头结点地址、旧数据、新数据

返回值:成功返回0,失败返回-1

int link_updata_value(Node_ptr L,datatype old,datatype new)
{//查找逻辑int post=link_find_value(L,old);//判断逻辑if(post==-1){return -1;}//修改逻辑link_updata_post(L,post,new);return 0;
}

单向链表反转

int link_reverse(Node_ptr );

函数功能:反转链表(头结点除外)

参数:链表头结点地址

返回值:成功返回0,失败返回-1

Node_ptr H=L->next;   //H记录第一个节点地址
L->next=NULL;      //清空头节点
while(H!=NULL)   //遍历
{Node_ptr q=H; //记录H的指向,搬运作用H=H->next;//头插形式插入q->next=L->next;L->next=q;
}

链表释放

void link_free(Node_ptr);

函数功能:释放链表所有节点(包括头结点)

参数:链表头结点地址

返回值:void

//释放逻辑
while(!link_empty(L))
{//调用头参函数link_delete_head(L);
}
//释放头节点,置空
free(L);
L=NULL;

完整代码

linklist.h 

#ifndef LINKLIST_H
#define LINKLIST_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int datatype;//定义数据域类型
typedef struct Node
{union{int len;  //头结点数据域datatype data; //普通节点数据域};struct Node *next;   //节点指针域
}Node,*Node_ptr;
//创建单向链表
Node_ptr linklist_create();
//链表判空操作
int link_empty(Node_ptr );
//创建节点
Node_ptr Node_apply(datatype ); 
//单向链表头插
int link_insert_head(Node_ptr ,datatype );
//单向链表按位置查找返回地址
Node_ptr link_find_post(Node_ptr ,int );
//链表的遍历
void show(Node_ptr );
//链表任意位置插入
int link_insert_post(Node_ptr ,int ,datatype);
//链表头删
int link_delete_head(Node_ptr );
//任意位置删除
int link_delete_post(Node_ptr ,int );
//按值查找返回位置
int link_find_value(Node_ptr ,datatype );
//按位置修改
int link_updata_post(Node_ptr ,int ,datatype);
//按值修改
int link_updata_value(Node_ptr,datatype,datatype);
//单向链表反转
int link_reverse(Node_ptr );
//
//链表的释放 
void link_free(Node_ptr);#endif

linklist.c

#include"linklist.h"
//此处头结点的地址都用l表示
//其他节点用p/pa表示//创建单向链表
Node_ptr linklist_create()
{   //申请一个头结点的空间Node_ptr l=(Node_ptr)malloc(sizeof(Node));if(l==NULL){printf("创建链表失败\n");return NULL;		}//头结点初始化l->len=0;//初始化长度为0l->next=NULL;//初始化指针为空,防止野指针printf("创建链表成功\n");return l;
}
//链表判空操作
//链表为空返回1,非空返回0
int link_empty(Node_ptr l)
{   //判断链表传入地址是否为空if(l==NULL){printf("链表不合法\n");return -1;}//通过判断头结点的后继节点指针是否为空return l->next==NULL;
}
//创建节点
//成功返回节点地址,失败返回空
Node_ptr Node_apply(datatype e)
{//堆区申请空间Node_ptr p=(Node_ptr)malloc(sizeof(Node));if(p==NULL){printf("节点空间申请失败\n");return NULL;}printf("节点申请成功\n");p->data=e; //初始化数据域p->next=NULL; //初始化指针为空return p; //封装好的节点地址
}
//单向链表头插
//成功返回0失败返回-1
//插入的数据是逆序,先进的在后面
int link_insert_head(Node_ptr L ,datatype e )
{//判断逻辑if(L==NULL){printf("插入失败\n");return -1;}//创建节点//pa指针接收节点的地址Node_ptr pa=Node_apply(e);if(pa==NULL){printf("插入失败\n");return -1;}//头插逻辑pa->next=L->next;//先继承头节点的指向L->next=pa;  //再将头节点指针指向插入的节点//长度自增L->len++;printf("头插成功\n");return 0;
}
//单向链表查找
//成功返回地址,失败返回空
Node_ptr link_find_post(Node_ptr L,int post)
{//判断逻辑if(L==NULL||post<0||post>L->len){printf("查找失败\n");return NULL;}//查找逻辑Node_ptr q=L; //定义一个遍历指针for(int i=0;i<post;i++) //先移动再自加,所有不需要等于post{q=q->next;//指向下一个节点}//返回节点return q;
}
//链表的遍历
void show(Node_ptr L)
{//判断逻辑if(link_empty(L)){printf("遍历失败\n");}Node_ptr q=L->next; //遍历指针指向第一个节点while(q)  //如果遍历为空,结束遍历{printf("%-4d",q->data);//遍历数据q=q->next;//指向下一个节点}putchar(10);
}
//链表任意位置插入
//成功插入返回0,失败返回-1
int link_insert_post(Node_ptr L ,int post,datatype e)
{//判断逻辑if(L==NULL||post<1||post>L->len+1) //判断地址和插入逻辑的合理性{printf("插入失败1\n");return -1;}//创建节点Node_ptr p=Node_apply(e);if(p==NULL){printf("插入失败2\n");return -1;}//调用函数找到post-1的地址,用q接收Node_ptr q=link_find_post(L,post-1);//插入逻辑p->next=q->next; //插入节点继承post-1节点的指针指向q->next=p;    //psost-1节点指向插入节点//长度自增L->len++;printf("插入数据成功\n");return 0;
}
//链表头删
//成功返回0,失败返回-1
int link_delete_head(Node_ptr L)
{//判断逻辑if(link_empty(L)){printf("删除失败\n");return -1;}//p记录节点地址Node_ptr p=L->next;//删除逻辑,头节点指向下一个节点L->next=p->next;//释放节点free(p);p=NULL;//防止野指针//长度自减L->len--;printf("链表头删成功\n");return 0;
}
//任意位置删除
//成功返回0,失败返回-1
int link_delete_post(Node_ptr L,int post)
{//判断逻辑if(L==NULL||post<1||post>L->len){printf("按位置删除失败\n");return -1;}//遍历到post前驱节点,p接收post-1地址Node_ptr p=link_find_post(L,post-1);//删除逻辑//本质是p->next=(p->next)->next Node_ptr q=p->next; p->next=q->next;  //q被孤立//释放节点,置空free(q);q=NULL;//长度自减L->len--;printf("删除成功\n");return 0;
}
//按值查找返回位置
int link_find_value(Node_ptr L ,datatype e)
{//判断逻辑if(L==NULL||link_empty(L)){printf("查找失败\n");return -1;}//查找逻辑Node_ptr p=L->next; //p指向第一个节点for(int i=1;i<=L->len;i++) //遍历查找{	if(p->data==e)return i;p=p->next; //不匹配p往后移动}printf("未找到,查询失败\n");return -1;
}
//按位置修改
int link_updata_post(Node_ptr L,int post,datatype e)
{//判断逻辑if(L==NULL||link_empty(L)||post<0||post>L->len+1){printf("修改失败\n");return -1;}//查找逻辑,用p接收post地址Node_ptr p=link_find_post(L,post);//修改逻辑p->data=e;return 0;
}
//按值修改
int link_updata_value(Node_ptr L,datatype old,datatype new)
{//查找逻辑int post=link_find_value(L,old);//判断逻辑if(post==-1){return -1;}//修改逻辑link_updata_post(L,post,new);return 0;
}
//单向链表反转
int link_reverse(Node_ptr L)
{if(L==NULL||L->len<=1){printf("翻转失败\n");return -1;}Node_ptr H=L->next;   //H记录第一个节点地址L->next=NULL;      //清空头节点while(H!=NULL)   //遍历{Node_ptr q=H; //记录H的指向,搬运作用H=H->next;//头插形式插入q->next=L->next;L->next=q;}return 0;
}
//链表的释放
void link_free(Node_ptr L)
{//判断逻辑if (L=NULL){printf("释放失败\n");return;}//释放逻辑while(!link_empty(L)){//调用头参函数link_delete_head(L);}//释放头节点,置空free(L);L=NULL;printf("释放成功\n");
}

main.c

#include"linklist.h"
int main(int argc, const char *argv[])
{	//定义指针x接收申请空间的首地址	Node_ptr x=linklist_create();	if(x==NULL){printf("创建失败\n");}printf("创建链表成功\n");printf("%d\n",link_empty(x));//Node_apply(e);//头插link_insert_head(x,1);link_insert_head(x,2);link_insert_head(x,3);link_insert_head(x,4);printf("%d\n",x->len);//链表查找//指针q接收地址Node_ptr q=link_find_post(x,2);printf("%d\n",q->data);printf("11111\n");show(x);link_insert_post(x,2,99);show(x);link_delete_head(x);show(x);link_delete_post(x,3);show(x);printf("%d\n",link_find_value(x,3));link_updata_post(x,3,88);show(x);link_updata_value(x,3,77);show(x);link_reverse(x);show(x);link_free(x);return 0;
}

http://www.dtcms.com/a/292602.html

相关文章:

  • 【科研绘图系列】R语言绘制柱状堆积图
  • 基于 Vue,SPringBoot开发的新能源充电桩的系统
  • 豪鹏科技锚定 “AI + 固态” 赛道:从电池制造商到核心能源方案引领者的战略跃迁
  • mybatis拦截器实现唯一索引的动态配置
  • 网络基础DAY16-MSTP-VRRP
  • git reset --soft和 git reset --mixed的主要区别
  • 智能制造——解读制造业企业数字化转型实施指南2025【附全文阅读】
  • libgmp库(GNU高精度算术库)介绍
  • 算法训练营day28 贪心算法②122.买卖股票的最佳时机II、55. 跳跃游戏、 45.跳跃游戏II 、1005.K次取反后最大化的数组和
  • Web服务器(Tomcat、项目部署)
  • 0722 数据结构顺序表
  • 循环神经网络--NLP基础
  • <另一种思维:语言模型如何展现人类的时间认知>总结
  • 大型语言模型(Large Language Models,LLM)
  • Science Robotics 机器人成功自主完成猪胆囊切除手术
  • vue3 动态判断 el-table列 用 v-if 是否显示
  • 微算法科技(NASDAQ: MLGO)探索优化量子纠错算法,提升量子算法准确性
  • 4.组合式API知识点(2)
  • 计算机视觉领域的AI算法总结——目标检测
  • C语言:循环结构
  • PePeOnTron上线 Binance Alpha:中文社区正走出自己的Web3之路
  • 基于网络爬虫的在线医疗咨询数据爬取与医疗服务分析系统,技术采用django+朴素贝叶斯算法+boostrap+echart可视化
  • 论文略读:Arcee’s MergeKit: A Toolkit for Merging Large Language Models
  • 电商开放平台获取商品数据返回信息详解
  • 旷视科技视觉算法面试30问全景精解
  • 飞算科技:用AI与数智科技,为产业数字化转型按下“加速键”
  • proxmox 解决docker容器MongoDB创建报错MongoDB 5.0+ requires a CPU with AVX support
  • 【集群】MySQL的主从复制了解吗?会有延迟吗,原因是什么?
  • 【无标题】AI视频-剧本篇学习笔记
  • 【面试】Redis分布式ID与锁的底层博弈:高并发下的陷阱与破局之道