C语言单链表的算法之插入节点

一:访问各个节点中的数据

        (1)访问链表中的各个节点的有效数据,这个访问必须注意不能使用p、p1、p2,而只能使用phead

        (2)只能用头指针不能用各个节点自己的指针。因为在实际当中我们保存链表的时候是不会保存各个节点的指针的,只能通过头指针来访问链表节点

        (3)前一个节点的pNEXT指针能帮助我们找到下一个节点

#include <stdio.h>        
#include <string.h>        
#include <stdlib.h>        //构建一个链表的节点
struct node
{int datas;                      //有效数据struct node *pNEXT;             //指向下一个节点的指针};int main(void)
{//定义头指针struct node *phead = NULL;//创建一个链表节点struct node *p = (struct node *)malloc(sizeof(struct node));        if(NULL == p)                //检查申请结果是否正确{printf("malloc error!\n");        return -1;}//memset(p,0,sizeof(struct node));          bzero(p,sizeof(struct node));            //清理申请到的堆内存//填充节点p->datas = 1;                            //填充数据区p->pNEXT = NULL;                         //将来要执行下一个节点的首地址phead = p;                              //将本节点和前面的头指针关联起来//创建一个链表节点并和上一个节点关联起来struct node *p1 = (struct node *)malloc(sizeof(struct node));        if(NULL == p1)                //检查申请结果是否正确{printf("malloc error!\n");        return -1;}//memset(p,0,sizeof(struct node));          bzero(p1,sizeof(struct node));            //清理申请到的堆内存//填充节点p1->datas = 1;                            //填充数据区p1->pNEXT = NULL;                         //将来要执行下一个节点的首地址p-pNEXT>= p1;                            //将本节点和前面的节点关联起来//再创建一个链表节点并和上一个节点关联起来struct node *p2 = (struct node *)malloc(sizeof(struct node));        if(NULL == p2)                //检查申请结果是否正确{printf("malloc error!\n");        return -1;}//memset(p2,0,sizeof(struct node));          bzero(p2,sizeof(struct node));            //清理申请到的堆内存//填充节点p2->datas = 1;                            //填充数据区p2->pNEXT = NULL;                         //将来要执行下一个节点的首地址p1-pNEXT>= p2;                           //将本节点和前面的节点关联起来//访问链表节点的第一个节点的有效数据printf("phead->p->datas = %d\n",phead->datas);printf("p->datas =  %d\n",p->datas);//访问链表节点的第二个有效数据printf("phead->pNEXT->datas =%d\n",phead->pNEXT->datas);printf("p1->datas = %d\n",p1->datas);//访问链表节点的第三个有效数据printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->datas);printf("p2->datas = %d\n",p2->datas);return 0;}

二:将创建的节点封装成一个函数

        (1)封装时的关键就是函数的接口(函数参数和返回值)的设计

           

#include <stdio.h>        
#include <string.h>        
#include <stdlib.h>        //构建一个链表的节点
struct node
{int datas;                      //有效数据struct node *pNEXT;             //指向下一个节点的指针};/****************************************
函数名:create
作用:创建一个链表节点
返回值:p 指针,指针指向本函数创建的一个节点的首地址
参数:
****************************************/
struct node *create(int a)
{struct node *p = (struct node *)malloc(sizeof(struct node));if(NULL == p){printf("malloc error!\n");return NULL;}memset(p,0,sizeof(struct node));  //bzero(p,sizeof(struct node));p->datas = a;p->pNEXT = NULL;return p;int main(void)
{//定义头指针struct node *phead = NULL;//调用函数实现创建链表节点并将数据放到有效数据区                                phead = create(100);          //调用一次函数,创建一个链表节点返回节点首地址给头指针phead->pNEXT = create(200);   //再次创建一个链表节点返回节点首地址给上一个节点的指针 phead->pNEXT->pNEXT = create(300); //同上printf("phead->p->datas = %d\n",phead->datas);        //printf("p->datas =  %d\n",p->datas);        //使用功能函数创建链表节点就不能再使用//节点指针访问有效数据区,只能通过头    //指针                printf("phead->pNEXT->datas =%d\n",phead->pNEXT->datas);//printf("p1->datas = %d\n",p1->datas);printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->datas);//printf("p2->datas = %d\n",p2->datas);return 0;}}

 运行结果:

     

三:从链表头部插入新节点

  (1)思路:第一步:新节点的next指向原来的第一个节点

                      第二步:头指针的next指向新节点

                      第三步:头节点的计数要加一     

                     

  (2)代码示例:

        

#include <stdio.h>
#include <string.h>
#include <stdlib.h>struct node
{int datas;struct node *pNEXT;};struct node *create(int a)
{struct node *p = (struct node *)malloc(sizeof(struct node));if(NULL == p){printf("malloc error!\n");return NULL;}memset(p,0,sizeof(struct node));  //bzero(p,sizeof(struct node));p->datas = a;p->pNEXT = NULL;return p;}void insert_tail(struct node *phead,struct node *new)
{struct node *p = phead;int cat = 0;while(NULL !=  p->pNEXT){p = p->pNEXT;cat++;}p->pNEXT = new;phead->datas = cat +1;}void insert_head(struct node *head,struct node *new)
{new->pNEXT =  head->pNEXT;            //新节点的next指向之前的第一个节点head->pNEXT = new;                    //头节点的next指向新节点地址head->datas += 1;                    //头节点的计数加一}int main(void)
{struct node *phead = create(0);insert_head(phead,create(1));insert_head(phead,create(2));insert_head(phead,create(3));/*phead = create(100);phead->pNEXT = create(200);phead->pNEXT->pNEXT = create(300);*/printf("phead->p->datas = %d\n",phead->datas);//printf("p->datas =  %d\n",p->datas);printf("phead->pNEXT->datas =%d\n",phead->pNEXT->datas);//printf("p1->datas = %d\n",p1->datas);printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->datas);//printf("p2->datas = %d\n",p2->datas);printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->pNEXT->datas);//printf("p2->datas = %d\n",p2->datas);return 0;}

 运行结果:

        

四:从链表尾部插入新节点

        (1)思路:从头指针往后开始遍历指针指向的地址判断是不是NILL,直到最后一个节点,因为最后一个节点的是指向NULL的,所以遍历结束,然后将最后一个节点的指针指向新创建的节点

#include <stdio.h>
#include <string.h>
#include <stdlib.h>//构建一个链表的节点
struct node
{int datas;struct node *pNEXT;};//创建一个链表节点
struct node *create(int a)
{struct node *p = (struct node *)malloc(sizeof(struct node));if(NULL == p){printf("malloc error!\n");return NULL;}memset(p,0,sizeof(struct node));  //bzero(p,sizeof(struct node));p->datas = a;p->pNEXT = NULL;return p;}//从尾部插入节点
void insert_tail(struct node *phead,struct node *new)
{struct node *p = phead;        //定义临时指针变量//循环遍历指针while(NULL !=  p->pNEXT){p = p->pNEXT;}p->pNEXT = new;    //节点尾部指针指向新节点}int main(void)
{struct node *phead = create(100);        //由于实现尾部插入判断是否是最后一个节点//所以如果将头指针指向NULL那么程序就出错了//这里就先创建一个节点让头指针指向它insert_tail(phead,create(200));          //再从单链接尾部插入节点insert_tail(phead,create(300));          //同上/*phead = create(100);phead->pNEXT = create(200);phead->pNEXT->pNEXT = create(300);*/printf("phead->p->datas = %d\n",phead->datas);//printf("p->datas =  %d\n",p->datas);printf("phead->pNEXT->datas =%d\n",phead->pNEXT->datas);//printf("p1->datas = %d\n",p1->datas);printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->datas);//printf("p2->datas = %d\n",p2->datas);return 0;}

(2)问题:因为我们在inserttail中直接默认了头指针指向的有一个节点,因此如果程序中直接
定义了头指针后就直接insert tail就会报段错误。我们不得不在定义头指针之后先create_node
创建一个新节点给头指针初始化,否则不能避免这个错误;但是这样解决让程序看起来逻辑有点
不太顺,因为看起来第一个节点和后面的节点的创建、添加方式有点不同。 

(3)链表还有另一种用法,就是把头指针指向的第一个节点作为头节点使用。头节点的特点是它紧跟在头指针后面;它的数据区是空的(有时候不是空的,用来存储链表节点个数);指针部分指向下一个节点(第一个链表节点)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>//构建一个链表的节点
struct node
{int datas;struct node *pNEXT;};//创建一个链表节点
struct node *create(int a)
{struct node *p = (struct node *)malloc(sizeof(struct node));if(NULL == p){printf("malloc error!\n");return NULL;}memset(p,0,sizeof(struct node));  //bzero(p,sizeof(struct node));p->datas = a;p->pNEXT = NULL;return p;}//从尾部插入节点
void insert_tail(struct node *phead,struct node *new)
{struct node *p = phead;        //定义临时指针变量int cat = 0;                   //创建一个计数器变量 //循环遍历指针while(NULL !=  p->pNEXT){p = p->pNEXT;cat++;                 //每循环一次加一}p->pNEXT = new;    //节点尾部指针指向新节点phead->datas = cat +1;}int main(void)
{struct node *phead = create(0);          //由于实现尾部插入判断是否是最后一个节点//所以如果将头指针指向NULL那么程序就出错了//这里就先创建一个头节点让头指针指向它insert_tail(phead,create(1));          insert_tail(phead,create(2));insert_tail(phead,create(3));/*phead = create(100);phead->pNEXT = create(200);phead->pNEXT->pNEXT = create(300);*/printf("phead->p->datas = %d\n",phead->datas);            //节点数printf("phead->pNEXT->datas =%d\n",phead->pNEXT->datas);  //第一个节点数据区数据printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->datas);   //第二个printf("phead->pNEXT->datas = %d\n",phead->pNEXT->pNEXT->pNEXT->datas);  //三return 0;}

运行 结果:链表节点数 3   第一个节点数据区为1   第二个为2 第三个为3

(4)这样看来,头节点确实和其他节点不同。我们在创建一个链表时添加节点的方法也不同。头
节点在创建头指针时一并创建并且和头指针关联起来;后面的真正的存储数据的节点用节点添加
的函数来完成,譬如insert tail。

(5)链表有没有头节点是不同的。体现在链表的插入节点、删除节点、遍历节点、解析链表的各
个算法函数都不同。所以如果一个链表设计的时候就有头节点那么后面的所有算法都应该这样来
处理:如果设计时就没有头节点,那么后面的所有算法都应该按照没有头节点来做。实际编程中
两种链表都有人用,所以程序员在看别人写的代码时一定要注意看它有没有头节点

注意:注意在写代码过程中的箭头符号,和说话过程中的指针指向。这是两码事,容易搞混箭头符号实质是用指针来访问结构体,所以箭头的实质是访问结构体中的成员。清楚的来说程序中的箭头和链表的连接没有任何的关系;链表中的节点通过指针指向来连接,编程中表现为赋值语句(用=来连接),实质是把最后一个节点的首地址,赋值给前一个节点中的pnext元素作为值

链表可以从头部插入,也可以尾部插入,也可以两头插入。对链表来说几乎没有差别,但是有时候对业务逻辑有差别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/35981.shtml

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

相关文章

【嵌入式Linux】i.MX6ULL GPIO 中断服务函数注册与编写

文章目录 1 外部中断初始化与中断服务函数1.2 外部中断初始化函数 exti_init1.2.1 GPIO引脚配置1.2.2 中断使能与注册1.2.3 GIC_EnableIRQ()函数的分析 1.3 中断服务函数 gpio1_io20_irqhandler1.3.1 消抖处理1.3.2 中断事件处理1.3.3 清除中断标志 2 BUG处理2.1 问题描述2.2 解…

网易Filmly网盘影片播放器安卓TV版

我们在观看网盘内的影视时&#xff0c;想要高清/原画质观看视频&#xff0c;甚至倍速功能往往都需要开通网盘会员才可以&#xff0c;否则你只能使用”马赛克”画质观看。 最近网易上线了一款播放器&#xff1a;Filmly &#xff0c;它支持直连网盘影视资源&#xff0c;可以高速…

深入理解计算机系统 CSAPP 家庭作业7.12

A:refptr (unsigned)(ADDR(r.symbol) r.addend - refaddr) 0x4004f8 (-4) - 0x4004ea 0xa B:refaddr 0x4004d0 0xa 0x4004da refptr 0x400500 (-4) - 0x4004da 0x22 ​​​​​​​

Python24 机器学习之决策树

1.什么是机器学习&#xff1f; 机器学习是人工智能&#xff08;AI&#xff09;的一个分支&#xff0c;它使计算机系统能够从经验中学习并根据这些学习的数据做出决策或预测&#xff0c;而无需进行明确的编程。简而言之&#xff0c;机器学习涉及算法和统计模型的使用&#xff0…

Hugo Barra对Apple Vision Pro 硬件和软件的详细评述

原文&#xff1a;hugo.blog/2024/03/11/vision-pro 这篇文章的作者是Hugo Barra。Hugo Barra曾是Meta公司&#xff08;前身为Facebook&#xff09;旗下Oculus VR/AR团队的负责人。他在2017年至2020年期间领导了Oculus的团队&#xff0c;参与了多个VR头显的开发和发布。Hugo Bar…

使用提示词调教AI

“AI 是我们的数字员工&#xff0c;了解员工的秉性 &#xff0c; 从调教提示词开始。” 网上流传最广的提示词方法论&#xff0c;是“你需要给大模型一个角色”。这确实是一个好的策略&#xff0c;因为小学老师&#xff0c;大学老师这样的角色&#xff0c;预设很多背景信息。这…

【数学建模】 函数极值与规划模型

文章目录 函数极值与规划模型1. 线性代数和线性规划的联系1.1 线性代数的基本概念1.2 线性规划的基本概念1.3 线性代数与线性规划的联系矩阵和向量线性方程组单纯形法内点法凸优化 1.4 例子 2. Numpy有关矩阵运算示例2.1 矩阵的创建2.2 矩阵的基本运算2.3 矩阵的合并2.4 矩阵的…

Linux系统之nice命令的基本使用

Linux系统之nice命令的基本使用 一、nice命令介绍1.1 nice命令简介1.2 进程优先级介绍 二、nice命令基本语法2.1 nice命令的help帮助信息2.2 nice命令选项解释 三、nice命令的基本使用3.1 查看进程优先级3.2 使用nice启动进程3.3 提高优先级 四、注意事项 一、nice命令介绍 1.…

如何制作自己的网站

制作自己的网站可以帮助个人或组织在互联网上展示自己的品牌、作品、产品或服务。随着技术的发展&#xff0c;现在制作网站变得越来越简单。下面是一个简单的步骤指南&#xff0c;帮助你制作自己的网站。 1. 确定你的网站需求和目标 在开始之前&#xff0c;你需要明确你的网站的…

CSS Grid网格布局

一、前言 二、Grid布局 1、基本介绍 2、核心概念 &#xff08;1&#xff09;网格容器 &#xff08;2&#xff09;网格元素 &#xff08;3&#xff09;网格列 &#xff08;4&#xff09;网格行 &#xff08;5&#xff09;网格间距 &#xff08;6&#xff09;网格线 三…

基于PHP的酒店管理系统(改进版)

有需要请加文章底部Q哦 可远程调试 基于PHP的酒店管理系统(改进版) 一 介绍 此酒店管理系统(改进版)基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端jquery插件美化。系统角色分为用户和管理员。系统在原有基础上增加了注册登录注销功能&#xff0c;增加预订房间图片…

Claude走向开放

Claude的愿景一直是创建能够与人们协同工作并显著提升他们工作流程的人工智能系统。朝着这一方向迈进&#xff0c;Claude.ai的专业版和团队版用户现在可以将他们的聊天组织到项目中&#xff0c;将精选的知识和聊天活动整合到一个地方&#xff0c;并且可以让团队成员查看他们与C…

什么是期货基金?

期货基金&#xff0c;是指广大投资者将资金集中起来&#xff0c;委托给专业的期货投资机构&#xff0c;并通过商品交易顾问进行期货投资交易&#xff0c;投资者承担投资风险并享有投资利润的一种集合投资方式。期货基金的投资对象主要有两大类商品&#xff1a;期货与金融期货。…

django学习入门系列之第三点《案例 商品推荐部分》

文章目录 划分区域搭建骨架完整代码小结往期回顾 划分区域 搭建骨架 /*商品图片&#xff0c;父级设置*/ .slider .sd-img{display: block;width: 1226px;height: 460px; }<!-- 商品推荐部分 --> <!--搭建出一个骨架--> <div class"slider"><di…

提高开发效率之——工具介绍

一 . SerialDebug 串口调试工具 SerialDebug 是一个串口调试工具&#xff0c;它主要用于帮助电子工程师和软件开发者进行串口通信的调试工作。以下是 SerialDebug 工具的一些主要作用和特点: 基础串口通信功能&#xff1a;提供打开、关闭、接收、发送数据的基础串口操作。 数…

.NET C# 使用OpenCV实现人脸识别

.NET C# 使用OpenCV实现模型训练、人脸识别 码图~~~ 1 引入依赖 OpenCvSHarp4 - 4.10.0.20240616 OpenCvSHarp4.runtime.win - 4.10.0.20240616 2 人脸数据存储结构 runtime directory | face | {id}_{name} | *.jpg id - 不可重复 name - 人名 *.jpg - 人脸照片3 Demo 3.…

前置章节-熟悉Python、Numpy、SciPy和matplotlib

目录 一、编程环境-使用jupyter notebook 1.下载homebrew包管理工具 2.安装Python环境 3.安装jupyter 4.下载Anaconda使用conda 5.使用conda设置虚拟环境 二、学习Python基础 1.快排的Python实现 (1)列表推导-一种创建列表的简洁方式 (2)列表相加 2.基本数据类型及运…

FastGPT 调用Qwen 测试Hello world

Ubuntu 安装Qwen/FastGPT_fastgpt message: core.chat.chat api is error or u-CSDN博客 参考上面文档 安装FastGPT后 登录&#xff0c; 点击右上角的 新建 点击 这里&#xff0c;配置AI使用本地 ollama跑的qwen模型 问题&#xff1a;树上有3只鸟&#xff0c;开了一枪&#…

使用CDN方式创建Vue3.0应用程序

CDN 的全称是 content delivery network&#xff0c;即内容分发网络。它是构建在现在的互联网基础之上的一层智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发和调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c…

matlab量子纠缠态以及量子门操作下的量子态

前言 今天我们来聊聊题外话&#xff0c;量子纠缠&#xff0c;在目前物理分支中&#xff0c;要说最深&#xff0c;最能改变人类对宇宙影响的莫过于量子力学了&#xff0c;假如我们可以人为的对两个粒子施加纠缠态&#xff0c;那么我们将可以足不出户的完成对外界的操控 简介 …