定义

链式存储的线性表

头文件相关定义 

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

链表的函数 


注意事项 

1.创建节点时,需要初始化节点的数据域指针域

2.创建节点后需要判断地址查看是否创建成功

3.无论是声明何种函数都需要判断头节点是否为空

    如果长度发生改变需要添加长度逻辑

        //判断逻辑

        //功能逻辑

        (长度逻辑)

        //返回逻辑

4.任意位置的增删改查都需要判断插入位置是否合理

5.释放节点后,需要将指针置空防止野指针

6.遍历下一个节点的操作为p=p->next;

7.理解链表反转

8.节点不允许增删改查

创建单向链表

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.pswp.cn/diannao/92294.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92294.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/92294.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【第三节】Class与Style绑定

文章目录Class与Style绑定绑定HTML Class对象语法数组语法绑定内联样式对象语法数组语法自动添加前缀Class与Style绑定 数据绑定一个常见需求是操作元素的 class 列表和它的内联样式,因为它们都是属性&#xff0c;我们可以用 v-bind 处理它们:我们只需要计算出表达式最终的字符…

CMOS知识点 离子注入工艺

知识点8&#xff1a;离子注入是为了将掺杂剂&#xff08;如硼、磷等&#xff09;精确引入硅晶片的近表面区域&#xff0c;以改变其电学性质。工艺过程&#xff1a;电离与加速&#xff1a;掺杂剂原子在离子源中被电离&#xff08;带电&#xff09;&#xff0c;通过高压电场&…

从安装到上手:Ubuntu 22.04 玩转 Containerd 2.1.3 容器运行时

Containerd 是一款支持 OCI 规范的容器运行时&#xff0c;注重容器部署和生命周期管理的简单性、健壮性与可移植性&#xff0c;常被嵌入到 Docker 和 Kubernetes 等系统中。本文将详细介绍在 Ubuntu 22.04 服务器上通过二进制包手动安装 Containerd 的完整步骤&#xff0c;包括…

Hadoop与云原生集成:弹性扩缩容与OSS存储分离架构深度解析

Hadoop与云原生集成的必要性Hadoop在大数据领域的基石地位作为大数据处理领域的奠基性技术&#xff0c;Hadoop自2006年诞生以来已形成包含HDFS、YARN、MapReduce三大核心组件的完整生态体系。根据CSDN技术社区的分析报告&#xff0c;全球超过75%的《财富》500强企业仍在使用Had…

飞算科技:以创新科技引领数字化变革,旗下飞算 JavaAI 成开发利器

作为国家级高新技术企业&#xff0c;飞算科技专注于自主创新&#xff0c;在数字科技领域持续深耕&#xff0c;用前沿技术为各行业客户赋能&#xff0c;助力其实现数字化转型升级的飞跃。​飞算科技凭借深厚的技术积累&#xff0c;将互联网科技、大数据、人工智能等技术与实际应…

多线程Python爬虫:加速大规模学术文献采集

1. 引言 在学术研究过程中&#xff0c;高效获取大量文献数据是许多科研工作者和数据分析师的需求。然而&#xff0c;传统的单线程爬虫在面对大规模数据采集时&#xff0c;往往效率低下&#xff0c;难以满足快速获取数据的要求。因此&#xff0c;利用多线程技术优化Python爬虫&a…

NX717NX720美光固态闪存NX724NX728

美光NX系列固态闪存深度解析&#xff1a;技术、性能与市场洞察一、技术架构与核心创新美光NX系列固态闪存&#xff08;包括NX717、NX720、NX724、NX728&#xff09;的技术根基源于其先进的G9 NAND架构。该架构通过5纳米制程工艺和多层3D堆叠技术&#xff0c;实现了存储单元密度…

浅谈——C++和C#差异

虽然这个话题看着似乎有些关公战秦琼的味道&#xff0c;但是作为游戏开发者&#xff0c;C和C#一定是绕不开的两门语言。不过虽然说是比较二者差异&#xff0c;因为我学习的过程主要是先学C&#xff0c;所以我先基于C的认知&#xff0c;再来聊聊C#之中的不同。&#xff08;为什么…

rocky9-zabbix简单部署

目录 一、准备 1、&#xff08;rocky9&#xff09; 2、配置数据库 二、配置文件 1、导入初始架构与数据 2、配置相关文件 三、启动服务 1、浏览器访问 2、解决乱码问题 ​编辑 四、监控 ① 添加主机 1、修改配置文件 2、启动服务 3、网页添加 ②添加监控模块 1…

tabBar设置底部菜单选项、iconfont图标(图片)库、模拟京东app的底部导航栏

欢迎来到我的UniApp技术专栏&#xff01;&#x1f389; 在这里&#xff0c;我将与大家分享关于UniApp开发的实用技巧、最佳实践和项目经验。 专栏特色&#xff1a; &#x1f4f1; 跨平台开发一站式解决方案 &#x1f680; 从入门到精通的完整学习路径 &#x1f4a1; 实战项目经…

7.22总结mstp,vrrp

一、MSTP技术&#xfeff;&#xfeff;MSTI和MSTI域根&#xfeff;&#xfeff;MSTP中的端口角色3. MSTP工作原理 MSTP 计算方法• CST/IST的计算和RSTP类似 • MSTI的计算仅限于区域内 • MSTI计算参数包含在IST BPDU中&#xff0c;和IST的计 算同步完成&#xfeff;&#xfe…

【电脑】网卡的基础知识

网卡&#xff08;Network Interface Card, NIC&#xff09;是计算机中用于连接网络的关键组件之一&#xff0c;它负责管理和发送数据包到互联网或其他局域网设备。下面是一些关于网卡的详细知识&#xff1a;网卡的基本结构MAC地址&#xff1a;每个网卡都有一个唯一的物理地址&a…

IPv4枯竭时代:从NAT技术到IPv6的演进之路

&#x1f50d; 开发者资源导航 &#x1f50d;&#x1f3f7;️ 博客主页&#xff1a; 个人主页&#x1f4da; 专栏订阅&#xff1a; JavaEE全栈专栏 IPv4&#xff08;Internet Protocol version 4&#xff09;是互联网最核心的通信协议之一&#xff0c;自 1981 年正式标准化以来…

模式结构-微服务架构设计模式

需求&#xff08;Forces)结果上下文(Resulting context)相关模式(Related patterns)需求&#xff1a;必须解决的问题需求部分描述了必须解决的问题和围绕这个问题的特定上下文环境。需求有时候是相互冲突的&#xff0c;所以不能指望把他们全部都解决&#xff08;必须取舍&#…

30个常用的Linux命令汇总和实战场景示例

下面汇总常用的 30 个常用的 Linux 命令&#xff0c;每个都附有简要说明和典型示例&#xff0c;适合日常开发、服务器维护或系统学习使用。30 个常用的 Linux 命令汇总 一、文件与目录操作&#xff08;基础&#xff09;命令说明示例ls列出文件和目录ls -l 显示详细信息cd切换目…

Taro 网络 API 详解与实用案例

Taro 网络 API 详解与实用案例 在现代前端开发中&#xff0c;网络通信是不可或缺的一环。Taro 作为一款多端开发框架&#xff0c;提供了丰富且统一的网络 API&#xff0c;帮助开发者在小程序、H5、React Native 等多端环境下高效地进行数据交互。本文将详细介绍 Taro 的四大网…

Bitbucket平台的HTTP Access Tokens操作手册

在Bitbucket平台添加HTTP Access Tokens&#xff08;用于替代密码进行认证&#xff09;。 1. 登录Bitbucket并访问个人设置 打开 Bitbucket 并登录账号。点击右上角头像 → 选择 Manage account。 2. 生成Access Token 在左侧菜单中选择 Access tokens&#xff08;位于 Sec…

低成本、高泛化能力的无人机自主飞行!VLM-Nav:基于单目视觉与视觉语言模型的无地图无人机导航

作者&#xff1a;Gobinda Chandra Sarker1^{1}1, AKM Azad2^{2}2, Sejuti Rahman1^{1}1, Md Mehedi Hasan1^{1}1单位&#xff1a;1^{1}1达卡大学&#xff0c;2^{2}2伊玛目穆罕默德伊本沙特伊斯兰大学论文标题&#xff1a;VLM-Nav: Mapless UAV-Navigation Using Monocular Visi…

Docker Desktop 安装到D盘(包括wsl)

默认WSL虚拟机位置&#xff1a; C:\Users\<用户名>\AppData\Local\Docker\wsl重装DockerDesktop下载安装包Docker Desktop Installer.exe在D盘创建文件夹D:\Program Files\DockerDesktopD:\Program Files\DockerDesktop\data 在cmd运行 start /w "" "Dock…

网络协议(三)网络层 IPv4、CIDR(使用子网掩码进行网络划分)、NAT在私网划分中的应用

利用子网掩码进行子网划分 这是一个模拟搭建的私网&#xff0c;有俩台主机ab。现在主机a要给云端服务器发送一条消息&#xff0c;这条消息怎么才能到达云端服务器呢&#xff1f;确定这条数据中的源端为本地ip的9000端口&#xff0c;目的端为24.24.24.8888端口&#xff0c;首先&…