C语言单向链表的逆序输出

article/2025/9/20 18:12:02

               最近在学习链表,看到书上说可以采取每次在链表头部插入新增节点的方法,将链表逆序,也就是建立的链表节点内容与数据的输入顺序相反。我便来了兴趣,想着试试看,结果没搞懂,于是开始百度。看了几遍博客后终于是明白了,而后写作的兴趣又上来了。。。。一个初学者就算再怎么来了兴趣,也不可能写得很好,所以有不对的地方,欢迎大家指出!顺便这里附上一篇写得很好的博客:点击蓝色字体。我正是看了这篇博客才大概弄懂了链表逆序,还自己手画链表才理解的。

                博主要讲的单链表逆序有5种(感觉不止,但是博主只会5种):

一、用数组接收链表的数据,然后控制下标输出

        简单的说一下这个方法的思路吧:其实很简单,就是通过链表的遍历,将链表中的数据一一赋值给一个数组。然后控制下标进行输出。

         我看了几篇博客,发现他们都是用自定义的函数来介绍链表逆序的,这对初学者有些不友好(问就是我是初学者),所以我直接这里就拿一个最简单的动态链表运用来举例子,直接上代码:

#include<stdio.h>
#include<stdlib.h>//malloc()函数的头文件
struct node{//定义结构体int id;node *next;//尾指针
};
int main()
{node *head=(node*)malloc(sizeof(node));//为都指针head开辟空间node *s=head;//命名一个动态指针,且让它指向头指针     scanf("%d",&s->id);//进行数据输入while(s->id!=0){//当输入的数据不为0时,继续输入,当然,也可以用-1等其他的数字来代替,并不唯一s->next=(node*)malloc(sizeof(node));//s此时的节点已经被存入了一个数据,所以要开辟下   
/一个节点来进行下一个节点的输入s=s->next;//将刚指针s指向刚开辟的指针,实际就是将s代表的节点换为下一个节点//当然,之前的数据已经存到链表里面了scanf("%d",&s->id);//继续输入数据}s->next=NULL;//最后将尾节点的指针指向空,也就是NULLs=head;//令指针s重新指向头节点,后面遍历将值赋给数组int a[10000]={0},i=0;//定义数组while(s!=NULL){a[i++]=s->id;//给数组赋值s=s->next;}i--;//数组下标的运用for(;i>=0;i--){printf("%d ",a[i]);//输出开头第一个为0,之前说到的标记,也可以用一个条件语句让0不输出}return 0;
}

      简单介绍下malloc()函数:malloc()括号内就是指开辟空间的大小,只是为了完美的开辟一个不大不小,刚好合适的空间,我们用sizeof()语句来获取已经定义的结构体的大小最后就是malloc()函数返回的数据类型是(void*),所以我们在运用时要进行类型的强制转换,也就是在前面加上(node*)(node*是我定义的结构体的类型)

最后说一下这种方法的缺点:学过链表的都知道,链表与数组相比,最大的优势就是可以动态分配内存空间。所以这个方法的缺点就是太浪费空间。链表是可以无限输入输出的,但是通过数组来进行逆序输出,再无限也变得有限了,因为我们不知道输入的数据有多少个,只能提前定义一个比较大一点的数组来进行逆序。而数据少了,浪费空间;数据多了,数组空间不足。

二、用三个指针遍历单链表,将链接点一一进行反转

        如下图,这是一个单链表,上面是数据域,下面书指针域,第一个节点就是头节点,最后一个节点的尾指针指向NULL。

这个方法就是用三个指针将图中每个节点二点指向反向(也就是箭头反指)。看图:

 这样,将每一个节点的指向反转。将逆序前的头指针指向空,最后就可以得到逆序的链表了,下面是实现代码(用的例子都是一样的,只是链表的逆序方法不同,就不像第一个方法那样打那么多注释了):

#include<stdio.h>
#include<stdlib.h>
struct node{int id;node *next;
};
int main()
{node *head=(node*)malloc(sizeof(node));node *s=head;scanf("%d",&s->id);while(s->id!=0){ s->next=(node*)malloc(sizeof(node));s=s->next;scanf("%d",&s->id);}s->next=NULL;//node *p,*q,*r;//用三个指针将链表逆序 p=head;//将p、q指向链表的前两个节点 q=head->next;head->next=NULL;//链表逆序后原来的头指针变为空 while(q!=NULL){//将链表的顺序一个一个反转 ,因为链表原来 r=q->next;//的排序最后一个节点为空,所以当链表逆序完成后,q指向的节点其实为空q->next=p;//而p指向的节点就是逆序后的头节点p=q;q=r;}head=p;s=head;//让指针指向头节点开始逆序输出while(s!=NULL){//遍历逆序后的链表printf("%d ",s->id);s=s->next;}return 0;
}

要理解上面的代码最重要的是(博主的个人理解):要理解   指针->next=    其实就是上面两个图中的箭头,指针指向谁,箭头就指向谁,因为单链表中每个节点都只能指向一个节点,将一个节点的指针指向一个新的节点,那这个节点原来指向的那个节点的箭头就自动断开。

三、从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾。

还是得看图理解:

123456
132456
143256
154326
16543

2

654321

对于一条链表,从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,(N-1)次这样的操作结束之后就得到上图。

最后在将第一个节点连接到新表的结尾就完成链表的逆序了。

下面是实现代码:

#include<stdio.h>
#include<stdlib.h>
struct node{int id;node *next;
};
int main(){node *head=(node*)malloc(sizeof(node));node *s=head;scanf("%d",&s->id);while(s->id!=0){s->next=(node*)malloc(sizeof(node));s=s->next;scanf("%d",&s->id);}s->next=NULL;node *p,*q;p=head->next;while(p->next!=NULL){q=p->next;p->next=q->next;q->next=head->next;head->next=q;}            //在上面的表格中p->next=head;//将尾节点指向头节点,形成一个环,也就是将末尾的2与1相连head=p->next->next;//将6定义为头节点p->next->next=NULL;//然后将1和6之间的连接断开,也就是将节点1指向空,作为末尾s=head;//最后遍历输出while(s!=NULL){printf("%d ",s->id);s=s->next;}
}

四、用递归

                要用递归来进行逆序的话,就不得不使用自定义函数了:

#include<stdio.h>
#include<stdlib.h>
struct node{int id;node *next;
};
node *reversal(node*p){//定义函数if(p==NULL||p->next==NULL){//少于两个节点不需要反转return p;}node *newhead=reversal(p->next);//不断调用自身函数,最后头节点会变成原来的最后一个节点p->next->next=p;p->next=NULL;return newhead;
}
int main()
{node *head=(node*)malloc(sizeof(node));node *s=head;scanf("%d",&s->id);while(s->id!=0){s->next=(node*)malloc(sizeof(node));s=s->next;scanf("%d",&s->id);}s->next=NULL;head=reversal(head);//通过自定义函数获取逆序后的头结点s=head;while(s!=NULL){//一样的遍历输出printf("%d ",s->id);s=s->next;}return 0;
} 

五、用头插法不断将新的数据插入链表头部

直接看代码:

#include<stdio.h>
#include<stdlib.h>
struct node {int id;node *next;
};
int main(){node *head=(node*)malloc(sizeof(node));node *p=head;scanf("%d",&p->id);head->next=NULL;while(p->id!=0){//以0为结束标志node *q=(node*)malloc(sizeof(node));//开辟一个节点q->next=head;//将这个节点插入头节点head=q;p=q;//或是p=head也可以scanf("%d",&p->id);//重新对头节点进行输入}p=head;while(p!=NULL){printf("%d ",p->id);p=p->next;}
}


http://chatgpt.dhexx.cn/article/Kq7Ju5jQ.shtml

相关文章

样本方差与总体方差的区别

为什么80%的码农都做不了架构师&#xff1f;>>> 之前一直对于样本方差与总体方差的概念区分不清&#xff0c;对于前者不仅多了“样本”两个字&#xff0c;而且公式中除数是N-1&#xff0c;而不是N。现在写下这么写东西&#xff0c;以能彻底把他们的区别搞清楚。 总…

彻底理解样本方差为何除以n-1

设样本均值为&#xff0c;样本方差为&#xff0c;总体均值为&#xff0c;总体方差为&#xff0c;那么样本方差有如下公式&#xff1a; 很多人可能都会有疑问&#xff0c;为什么要除以n-1&#xff0c;而不是n&#xff0c;但是翻阅资料&#xff0c;发现很多都是交代到&#xff0c…

证明样本方差不是总体方差的无偏估计(1)

无偏估计是用样本统计量来估计总体参数时的一种无偏推断。估计量的数学期望等于被估计参数的真实值&#xff0c;则称此估计量为被估计参数的无偏估计&#xff0c;即具有无偏性&#xff0c;是一种用于评价估计量优良性的准则。无偏估计的意义是&#xff1a;在多次重复下&#xf…

总体方差与样本方差分母的小小区别,n还是n-1?

总体方差与样本方差分母的小小区别&#xff0c;n还是n-1&#xff1f; 引入方差概念方差计算无偏估计 样本方差公式相关参考链接 样本方差的自由度是n-1 引入 方差概念 方差是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量&#xff0c;用来度量随机变量和其数学期…

样本方差的与方差

之前做模型拟合的时候需要计算样本的方差和均值,Matlab的std函数算出来就是不对经,一看才知道matlab的给定的标准差计算公式是: For a random variable vector A made up of N scalar observations, the standard deviation is defined as where μ is the mean of A: The s…

总体样本方差的无偏估计样本方差为什么除以n-1

总体样本方差的无偏估计样本方差为什么除以n-1 本文链接&#xff1a; https://blog.csdn.net/qq_16587307/article/details/81328773 我们先从最基本的一些概念入手。 如下图&#xff0c;脑子里要浮现出总体样本&#xff0c;还有一系列随机选取的样本。只要是样本&#xff0c;…

有偏样本方差、无偏样本方差

1.有偏样本方差、无偏样本方差 笔记来源&#xff1a;Why Dividing By N Underestimates the Variance 1.1 为什么样本方差总是小于总体方差&#xff1f; 由于总体量太大&#xff0c;我们要耗费大量人力物力财力才可以或者永远无法了解总体情况&#xff0c;所以我们只能用样本…

C# 及excel中【总体方差】、【样本方差】的计算公式

一、数学公式 二、C#中的数学包 using MathNet.Numerics.Statistics; 三、【总体方差】和【样本方差】的计算 using System; using System.Linq;var myList new List<float> {1,3,4,5,6,7};display("要计算的数据"); display(myList);var pv myList.Popula…

用Python计算样本方差,总体方差,比较

1.样本方差 #样本方差&#xff0c;考虑自由度def f_sigma(x):# 通过Python定义一个计算变量波动率的函数# x&#xff1a;代表变量的样本值&#xff0c;可以用列表的数据结构输入n len(x)u_mean sum(x)/n #计算变量样本值的均值z [] #生成一个空列表for t in range(n):z.…

总体方差与样本方差

今天在计算一类数据的协方差时遇到个问题。数据如下&#xff1a; x1(0,0,0)’ x2(1,0,0)’ x3(1,0,1)’ x4(1,1,0)’ 这本是一件很容易的事&#xff0c;但我手算后用Matlab的cov函数验算了一下&#xff0c;发现结果竟然不一样&#xff0c;于是按照协方差公式&#xff0c;一…

统计学---之样本方差与总体方差的区别

前段日子重新整理了一下这个问题的解答&#xff0c;跟大家分享一下&#xff0c;如果有什么错误的话希望大家能够提出来&#xff0c;我会及时改正的&#xff0c;话不多说进入正题&#xff1a; 首先&#xff0c;我们来看一下样本方差的计算公式&#xff1a; 刚开始接触这个公式的…

为什么样本方差里面要除以(n-1)而不是n?

前段日子重新整理了一下这个问题的解答&#xff0c;跟大家分享一下&#xff0c;如果有什么错误的话希望大家能够提出来&#xff0c;我会及时改正的&#xff0c;话不多说进入正题&#xff1a; 首先&#xff0c;我们来看一下样本方差的计算公式&#xff1a; 刚开始接触这个公式的…

ECS_FDS小议贝塞尔校正(Bessel‘s Correction)

在学习概率论与数理统计的相关知识时&#xff0c;大家肯定会听到”贝塞尔校正&#xff08;Bessels Correction&#xff09;“这个名词&#xff0c;这是德国天文学家&#xff0c;数学家Friedrich Bessel在进行天体测量学研究时提出的一个方法。可能大家看到一个以人名命名的概念…

样本方差与总体方差

样本方差与总体方差 一、方差&#xff08;variance)&#xff1a;衡量随机变量或一组数据时离散程度的度量。 概率论中方差用来度量随机变量和其数学期望&#xff08;即均值&#xff09;之间的偏离程度。 统计中的方差&#xff08;样本方差&am…

完整的Axios封装-单独API管理层、参数序列化、取消重复请求、Loading、状态码...

前言 Axios 相信对Vue熟悉的铁汁对它不会感到陌生了&#xff08;当然不熟悉Vue你也可以认识它&#xff09;&#xff0c;这简直就是前端近年来的一大杀器&#xff0c;自从Vue2开始之后&#xff0c;官方推荐使用axios来进行网络请求&#xff0c;后面基本大部分Vue项目都能瞧见它…

Ajax介绍和Axios基本使用

Ajax介绍 Ajax本身就是Asynchronous JavaScript And XML的缩写&#xff0c;直译为&#xff1a;异步的JavaScript和XML。 在实际应用中Ajax指的是&#xff1a;不刷新浏览器窗口&#xff0c;不做页面跳转&#xff0c;局部更新页面内容的技术。 『同步』和『异步』是一对相对的…

Axios使用详解

文章目录 一、Promise的使用1. 基本语法2. Promise三种状态3. Promise链式调用1. 基本写法2. 使用静态方法3. 直接返回 4. Promise.all5. Promise.race 二、Axios使用1. 安装并引入2. 发送请求3. config配置4. 响应结构5. 并发请求6. 全局配置6. 创建实例7. 实例方法8. 拦截器请…

Uncaught (in promise) Error: Network Error at e.exports (axios.js:8:6410) at d.onerror (axio

axios报错&#xff1a; 原因&#xff1a; 后端没有给跨域权限&#xff0c;后端需要设置允许跨域的响应头&#xff0c;即可解决。 解决&#xff1a; node端设置响应头&#xff0c;解决跨域问题 。

axios封装

不要过度封装&#xff01;封装一个最简单的Axios&#xff01; - 掘金 (juejin.cn) 1 初始化 axios 实例 通过 create 方法我们得到了一个 axios 的实例&#xff0c;该实例上有很多方法&#xff0c;比如拦截器等等。我们创建实例的时候可以配置一些基础设置&#xff0c;比如基础…