链表常见操作:逆置(反转) .

逆置链表(顺序表和单链表) 目录 题目内容 算法分析 概要分析 函数: (1) 顺序表 (2)单链表 算法流程图 逆置顺序表流程图 逆置单链表流程图 源代码 顺序表代码 单链表代码 题目内容 试分别用顺序表和单链表作为存储结构,实现线性表就地逆置的操作,所谓“就地”,指辅助空间应为O(1)。 算法分析 顺序表:要将该表逆置,可以将表中的开始结点与终端结点互换,第二个结点与倒数第二个结点互换,如此反复... 阅读详情

链表中的一个很常见的操作是:链表的逆置,也叫链表的反转。

如:1->3->5->7->9 反转后是 9->7->5->3->1

方法一:使用指针


红色的箭头是新的变换,明白了操作原理就很好写代码了。

使用了三个指针:pre(前驱) cur(当前) rear(后继),经过以上的四步变换,目地是,使cur指向的节点成功逆置(反转)指向pre所指向的节点。后面的节点的逆置,是同样的。

代码是:

  1. void reverse(Node *&head)  
  2. {  
  3.     if (head == NULL || head->next==NULL)  //空或者只有一个元素不用逆置  
  4.         return;  
  5.     Node *pre, *cur, *rear;  
  6.     pre = head;  
  7.     cur = head->next;  
  8.     while (cur)  
  9.     {  
  10.         rear = cur->next;  
  11.         cur->next = pre;  
  12.         pre = cur;  
  13.         cur = rear;  
  14.     }  
  15.     //以下两步,很重要   
  16.     head->next = NULL;   //这一步会使新的尾节点的链域置空  
  17.     head = pre;   //head指针指向新的一头  
  18. }  
void reverse(Node *&head)
{
	if (head == NULL || head->next==NULL)  //空或者只有一个元素不用逆置
		return;
	Node *pre, *cur, *rear;
	pre = head;
	cur = head->next;
	while (cur)
	{
		rear = cur->next;
		cur->next = pre;
		pre = cur;
		cur = rear;
	}
	//以下两步,很重要
	head->next = NULL;   //这一步会使新的尾节点的链域置空
	head = pre;   //head指针指向新的一头
}

写一个完整的测试用例

  1. #include<stdio.h>     
  2. #include<stdlib.h>   
  3. typedef struct node  //节点类型定义    
  4. {  
  5.     int data;  
  6.     struct node *next;  
  7. }Node;  
  8. void printlist(Node *head)   //打印链表    
  9. {  
  10.     Node *p = head;  
  11.     while (p->next)  
  12.     {  
  13.         printf("%-4d->", p->data);  
  14.         p = p->next;  
  15.     }  
  16.     printf("%-4d\n", p->data);  
  17. }  
  18. void reverse(Node *&head)   //逆置    
  19. {  
  20.     if (head == NULL || head->next == NULL)  //空或者只有一个元素不用逆置    
  21.         return;  
  22.     Node *pre, *cur, *rear;  
  23.     pre = head;  
  24.     cur = head->next;  
  25.     while (cur)  
  26.     {  
  27.         rear = cur->next;  
  28.         cur->next = pre;  
  29.         pre = cur;  
  30.         cur = rear;  
  31.     }  
  32.     //以下两步,很重要     
  33.     head->next = NULL;  
  34.     head = pre;  
  35. }  
  36. int main()  
  37. {  
  38.     Node p9={ 9, NULL };  
  39.     Node p7={ 7, &p9 };  
  40.     Node p5={ 5, &p7 };  
  41.     Node p3={ 3, &p5 };  
  42.     Node p1={ 1, &p3 };  
  43.     Node *head = &p1;  
  44.     printf("原表是\n");  
  45.     printlist(head);  
  46.     printf("逆置\n");  
  47.     reverse(head);  
  48.     printlist(head);  
  49.     system("pause");  
  50.     return 0;  
  51. }  
#include<stdio.h>  
#include<stdlib.h>
typedef struct node  //节点类型定义  
{
	int data;
	struct node *next;
}Node;
void printlist(Node *head)   //打印链表  
{
	Node *p = head;
	while (p->next)
	{
		printf("%-4d->", p->data);
		p = p->next;
	}
	printf("%-4d\n", p->data);
}
void reverse(Node *&head)   //逆置  
{
	if (head == NULL || head->next == NULL)  //空或者只有一个元素不用逆置  
		return;
	Node *pre, *cur, *rear;
	pre = head;
	cur = head->next;
	while (cur)
	{
		rear = cur->next;
		cur->next = pre;
		pre = cur;
		cur = rear;
	}
	//以下两步,很重要  
	head->next = NULL;
	head = pre;
}
int main()
{
	Node p9{ 9, NULL };
	Node p7{ 7, &p9 };
	Node p5{ 5, &p7 };
	Node p3{ 3, &p5 };
	Node p1{ 1, &p3 };
	Node *head = &p1;
	printf("原表是\n");
	printlist(head);
	printf("逆置\n");
	reverse(head);
	printlist(head);
	system("pause");
	return 0;
}


运行:



思考:我们知道链表一般是带有头节点的,而这里我们没有使用头节点。那么,我们如何对一个带有头节点的链表进行逆置呢?逆置后的链表也是要带有头节点的哦。大家可以动手试试,不妨把代码写在评论里,互相参考下,看有什么细节的不同。(楼主的一个写法,在一楼,欢迎不吝赐教,thanks)


方法二:在递归中逆置(反转)

思路:在对当前节点逆置时,先递归地逆置其后继节点,然后将后继节点指向当前节点。

直接给一个测试用例:

  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. typedef struct node  
  4. {  
  5.     int data;  
  6.     struct node *next;  
  7. }Node;  
  8. void printlist(Node *head)  
  9. {  
  10.     Node *p = head;  
  11.     while (p->next)  
  12.     {  
  13.         printf("%-4d->", p->data);  
  14.         p = p->next;  
  15.     }  
  16.     printf("%-4d\n", p->data);  
  17. }  
  18. void reverseWithRecursion(Node *&head, Node *cur)    //递归逆置  
  19. {  
  20.     if (cur->next == NULL)   //最后一个元素是递归终止条件  
  21.     {  
  22.         head = cur;  
  23.         return;  
  24.     }  
  25.     Node *rear = cur->next;  
  26.     reverseWithRecursion(head, rear);  
  27.     rear->next = cur;  
  28.     //cur->next = NULL;    //句一,这一句可以注释掉   
  29. }  
  30. void reverse(Node *&head)  
  31. {  
  32.     if (head == NULL || head->next == NULL)   //为空或只有一个元素就结束   
  33.         return;  
  34.     Node *cur=head;  
  35.     reverseWithRecursion(head, cur);  
  36.     cur->next = NULL;    //句二,这一句可以注释掉,不过句一和句二必须保留一句  
  37. }  
  38. int main()  
  39. {  
  40.     Node *head = NULL;  
  41.     Node p8{ 8, NULL };  
  42.     Node p6{ 6, &p8 };  
  43.     Node p4{ 4, &p6 };  
  44.     Node p2{ 2, &p4 };  
  45.     Node p0{ 0, &p2 };  
  46.     head = &p0;  
  47.     printf("原链表\n");  
  48.     printlist(head);  
  49.     printf("逆置\n");  
  50.     reverse(head);  
  51.     printlist(head);  
  52.     system("pause");  
  53.     return 0;  
  54. }  
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
	int data;
	struct node *next;
}Node;
void printlist(Node *head)
{
	Node *p = head;
	while (p->next)
	{
		printf("%-4d->", p->data);
		p = p->next;
	}
	printf("%-4d\n", p->data);
}
void reverseWithRecursion(Node *&head, Node *cur)    //递归逆置
{
	if (cur->next == NULL)   //最后一个元素是递归终止条件
	{
		head = cur;
		return;
	}
	Node *rear = cur->next;
	reverseWithRecursion(head, rear);
	rear->next = cur;
	//cur->next = NULL;    //句一,这一句可以注释掉
}
void reverse(Node *&head)
{
	if (head == NULL || head->next == NULL)   //为空或只有一个元素就结束 
		return;
	Node *cur=head;
	reverseWithRecursion(head, cur);
	cur->next = NULL;    //句二,这一句可以注释掉,不过句一和句二必须保留一句
}
int main()
{
	Node *head = NULL;
	Node p8{ 8, NULL };
	Node p6{ 6, &p8 };
	Node p4{ 4, &p6 };
	Node p2{ 2, &p4 };
	Node p0{ 0, &p2 };
	head = &p0;
	printf("原链表\n");
	printlist(head);
	printf("逆置\n");
	reverse(head);
	printlist(head);
	system("pause");
	return 0;
}

运行:



对递归逆置函数的理解是最重要的,也是最难理解的。难点有:

  1. 句一的作用。这个初看很难让人明白,甚至误解。我们知道原链表的第一个节点的链域在最后要置空,但这里每次递归都置空,是否会出问题?画个图后,发现不会。我们对递归的过程要理解,并且得明白上一次的递归函数中的rear指向的正是这一次的cur,(它俩指向同一节点)。所以即使被置空了,当递归返回上一层时,该链域依然会被修改。当然,除了原链表的第一个节点(想想为什么?),这也是这句话的真实目地:让原链表的第一个节点的链域在最后被置空。
  2. 由上一点的分析,我们可以想到:为何不直接修改原链表第一个节点的链域呢?何必费心一路递归修改,这样会造成很多的操作是没必要的。事实上的确可以,这就是句二的作用,那就是说不用句一,只用句二就可以了。但它俩至少要有一个,从效率上看,推荐只使用句二。
  3. 第一个参数被设计成引用类型,它的意义:在递归到原链表的尾节点时,把head指向该曾经的尾节点(也就是新链表的第一个节点)。


C语言—链表的逆置 C语言—链表的逆置 组里考核题有这么一道题:创建一个链表,链表里的数据取随机数,现在要求把链表逆置,写出实现代码。 刚看到这道题的时候我第一想到的是交换指针实现,但是画了半天想不出来,为了过审核就用了最笨的值交换。就是把头和尾的值交换,头向后移,尾向前移,直到相遇。 后来组长除了这个值交换还说了两种方法:迭代逆置链表和递归逆置链表。 迭代逆置链表:从第一个节点开始依次改变节点指针,把原来... 阅读详情

相关推荐

104-数据结构——逆置链表的六种方法

方法一: void Reverse(List plist) { assert(plist != NULL); if(plist == NULL || plist->next == NULL || plist->next->next == NULL) { return ; } //设置p和q Node *p = plist->next; Node *q = p->next; //将头断开 plist->next = NULL; while(p !=

weixin_45964837的博客 614

链表逆置的两种方法

头插法逆置和三指针原地反转

lxylxylxy的博客 9044

单链表反转:从迭代、递归到头插法,详解四种实现与工程选型

链表是数据结构与算法中的基础概念,它以节点为单位,通过指针串联实现动态存储。其核心原理在于每个节点包含数据域和指向下一个节点的指针,这种非连续存储结构使得插入和删除操作高效。掌握链表操作的技术价值在于深入理解指针、内存管理以及递归与迭代的编程思想,这是构建复杂系统(如内存池、文件系统、LRU缓存)的基石。在实际应用场景中,单链表反转是检验程序员对指针和递归理解深度的经典问题,常出现在面试与算法实践中。本文围绕**迭代法**和**递归法**两种核心方法,结合**指针操作**的常见陷阱与调试技巧,系统讲解如何安

weixin_29913663的博客 236

链表逆置详细讲解(图文)

链表逆置   前言 链表逆置是初学时有困扰到我的难点. 由于链表头结点可放可不放数据,所以写代码时候**->next**用的云里雾里。 这里讲解头结点与第一结点区分的情况,即头结点你把它看作这个 链表的“文件名” 就行。 若头结点为L,则第一结点为L->next。   代码 void listReverse(linkedList &L) { node *p,*s; //1. p = L->next; L->next = NULL; while

qq_51366188的博客 3万+

55-将单链表原地逆置(三种方法)

void Reverse(HeadList *head) { if(head==NULL||head->next==NULL||head->next->next==NULL) return ; HeadList *s=NULL; HeadList *p=head->next; HeadList *q=p->next; while(p!=NULL) { p->next=s; s=p; p=q; if(q!=NULL) { q=q-&.

LINZEYU666的博客 5857

单链表的逆置(C++版)

单链表的逆置是一个很有趣的问题,同时也是很多公司在面试时经常会拿出来“为难”面试者的题,比如博主在面试Microsoft的时候就被问到了这个问题。 问题描述:写一个程序,创建一个单向链表,并通过逆置函数使得该链表的方向反转,即头变尾,尾变头。 比如一个链表是这样的:1 -> 2 -> 3 -> 4 -> 5,逆置后则变成:5 -> 4 -> 3 -> 2 -> 1。 分析:该问题可以有两种解

进击的程序员 2563

链表常见操作:逆置(反转)

链表中的一个很常见的操作是:链表的逆置,也叫链表的反转。 如:1->3->5->7->9 反转后是 9->7->5->3->1

CCPP Blog 1万+

手把手教你搞定MT6701磁编码器的SSI通信与CRC-6校验(附避坑代码)

本文详细介绍了MT6701磁编码器的SSI通信与CRC-6校验的实现方法,包括硬件连接、时序配置、数据读取和专用CRC-6算法。通过提供避坑代码和常见问题解决方案,帮助开发者快速掌握磁编芯片的调试技巧,确保通信稳定可靠。

weixin_30872337的博客 217

反转链表的几种常用方法

(1)迭代法反转链表 核心思想是设置三个指针分别指向(待被反转后指针指向的结点front指针域指向要反转的结点mid待被反转的结点last),从头结点开始通过三个指针的移动逐渐完成链表的反转 struct Link* Iteration(struct Link* head)//也可以从头结点开始 { struct Link*front=NULL;//使front指向首元结点前的位置 struct Link*mid=head;//mid指向首元结点 ...

TGRD4的博客 972

【软件分享】天若OCR文字识别V4.48(翻译功能免费)

软件简介 吾爱破解论坛大佬天若幽心开发的一款OCR文字识别工具。支持快速截图识别,以及文本翻译。 下载地址 蓝奏云盘:点击下载 百度网盘:点击下载(密码:4dm4) 坚果云盘:点击下载 天翼云盘:点击下载 微软云盘:点击下载 使用教程 1、下载后对压缩包进行解压 2、双击天若OCR文字识别.exe 3、发现桌面右下角出现软件图标 4、双击软件图标即可开始截图识别 原帖地址 https://www.52pojie.cn/thread-692917-1-1.html ...

XavierJ的博客 1万+

基于Java+Maven+Testng+RestAssured+Allure+Jenkins搭建一个接口自动化框架

2、有一个提取表达式列,通过编写每个接口的JSON提取表达式,后边在解析Excel时,对接口执行后的响应数据用该表达式提取出来,保存到环境变量,如果某些接口需要前置接口的响应数据,我们就可以从环境变量中获取该数据出来,从而解决了接口关联的问题。1、在之前介绍过全局配置类Contants中添加一个控制台日志开关控制权限,如果选择为false,则控制台不输出日志,将日志输出到allure报表,选择为true,则在控制台输出日志,不输出到allure报表。

专注于技术分享的博主 1183

剑指offer 06:从尾到头打印单链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 示例 1: 输入:head = [1,3,2] 输出:[2,3,1] 单链表结构如下: struct ListNode { int val; struct ListNode *next; }; 解法一:时间复杂度和空间复杂度都为O(n)。 不用修改链表的结构。 先计算出链表中的结点个数,然后开辟一个和链表节点个数相同的数组空间,将链表中每个结点的数据域的值放到数组中然后再将数组的地址返回即可。 C语言代码如下.

csdn_edition的博客 274

PX4飞控 vs 大疆A3:开源与闭源方案在无人机硬件架构中的实战对比

本文深入对比了PX4飞控与大疆A3在无人机硬件架构上的差异,分析了开源与闭源方案在工业级无人机开发中的优劣势。通过详细的硬件配置、传感器兼容性、扩展能力及性能测试数据,为开发者提供选型指南,特别适合需要自定义算法和复杂功能集成的项目。

a3b4c5的博客 886

单链表反转(逆置)——(四种方法实现)

链表逆置就是把最后以一个提到坐前面,倒数第二个放到第二个……直到第一个到最后一个。 由于链表没有下标,所以不能借助下表来实行数据的逆置,要靠空间的转移来完成链表的逆置 这里采用没有头节点的链表来实现逆置。 第一种——头插法 算法思想:逆置链表初始为空,表中节点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。 #include <stdio.h> #include <stdli...

m0_58397166的博客 8万+

2024广东省职业技能大赛云计算——集群部署GitLab

题目是这样的:在Kubernetes集群中新建命名空间gitlab-ci,将GitLab部署到该命名空间下,Deployment和Service名称均为gitlab,以NodePort方式将80端口对外暴露为30880,设置GitLab服务root用户的密码为admin@123,将项目包demo-2048.tar.gz导入到GitLab中并命名为demo-2048。GitLab是一个功能强大且灵活的 DevOps 平台,为开发团队和企业提供了从代码管理到持续集成、交付和部署的一整套解决方案。

kuuuugua的博客 4395

实时数字人SoulX-FlashHead 音视频不对齐解决

【代码】实时数字人SoulX-FlashHead 音视频不对齐解决。

jacke121的专栏 200

单链表就地逆置(C语言实现)

算法实现带头结点单链表的就地逆置问题 #include<stdio.h> #include<stdlib.h> typedef struct Lnode{ int data; struct Lnode *next; }Lnode,*LinkList; void InitList(LinkList &L) { L=(LinkList)malloc(sizeof(Lnode)); L->next=NULL; } void CreatLinkList(Link

weixin_42586927的博客 6428

python实现下载和离线安装包环境

导出当前电脑python安装的所有包列表requirement.txt。

m0_60352504的博客 1676

实现带头结点的单链表元素就地逆置

数据结构算法基础题2-1

weixin_60956192的博客 5582

基于YOLOv11的农作物病虫害检测系统设计与实现

我们使用公开的IP102病虫害数据集作为基础,该数据集包含102种病虫害类别,覆盖水稻、小麦、玉米等多种主要农作物。图像数量:75,222张类别数:102图像分辨率:从640×480到4000×3000不等标注格式:PASCAL VOC格式此外,我们还收集了部分田间实际拍摄的图像以增强模型泛化能力。

YOLO 595

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

单链表逆置(头插法图解)

单链表逆置(头插法图解) 算法思想: 首先将头结点摘下,重新构造链表,然后原链表中的结点依次头插到新链表中,如此循环,直到链表为空,即可逆置链表。

程序员小木的博客 1万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

链表的逆置

数据结构实验之链表三:链表的逆置 Description 输入多个整数,以-1作为结束标志,顺序建立一个带头结点的单链表,之后对该单链表的数据进行逆置,并输出逆置后的单链表数据。 Input 输入多个整数,以-1作为结束标志。 Output 输出逆置后的单链表数据。 Sample Input 12 56 4 6 55 15 33 62 -1 Output 62 33 15 55 6 4 56 12...

qq_45666654的博客 2348

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

6-27 链表逆置 (20 分)

本题要求实现一个函数,将给定单向链表逆置,即表头置为表尾,表尾置为表头。链表结点定义如下: struct ListNode { int data; struct ListNode *next; }; 函数接口定义: struct ListNode *reverse( struct ListNode *head ); 其中head是用户传入的链表的头指针;函数reverse将链表...

asdf8759的博客 7841

【数据结构】单链表逆置:头插法图解

利用头插法能重新建立带头节点的新链表 下面简单介绍一下,算法思想结合图示看 算法思想:逆置链表初始为空,表中节点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。 LNode *Inverse(LNode *L) { LNode *p, *q; p = L->next; L->nex...

明月沉江春雾晓 7万+

PTA 链表逆置(函数题)

6-1 链表逆置 (16分 本题要求实现一个函数,将给定单向链表逆置,即表头置为表尾,表尾置为表头。链表结点定义如下: struct ListNode { int data; struct ListNode *next; }; 函数接口定义: struct ListNode *reverse( struct ListNode *head ); 其中head是用户传入的链...

好学者的博客 5296

单链表的原地逆置

单链表的原地逆置大概有两种方法,一是头插法,此方法需要维持两个辅助指针;二是维持三个辅助指针一次遍历进行逆置。 头插法 由于头插法的性质,将所有结点按顺序进行头插法,则完成逆置。 初始状态如下图。 1、首先用p指针指向N1,然后将Head->next设为NULL,如下图。 2、此时,设置r指针指向p->next,也就是N2,将p指针指向的N1的next设置为NULL,然后将p指向的结点N1用头插法插入到Head->next,如下图。 3、此时,令p=r,r=r->next,所以

weixin_43926088的博客 6312
上一篇: 中断下半部的处理
下一篇: 编译android源码遇到的问题
TopicDev
博客等级 码龄14年 128粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值