百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT文章 > 正文

数据结构与算法 目录 《数据结构与算法详解》

chenpack 2025-06-26 20:00 29 浏览 0 评论

数据结构与算法完整版 | 超详细图解,看这一篇就够了

反转链表

反转一个单链表。

输入: 1->2->3->4->5 
输出: 5->4->3->2->1

解法1:

迭代,重复某一过程,每一次处理结果作为下一次处理的初始值,这些初始值类似于状态、每次处理都会改变状态、直至到达最终状态

数据结构与算法 目录 《数据结构与算法详解》

从前往后遍历链表,将当前节点的next指向上一个节点,因此需要一个变量存储上一个节点prev,当前节点处理完需要寻找下一个节点,因此需要一个变量保存当前节点curr,处理完后要将当前节点赋值给prev,并将next指针赋值给curr,因此需要一个变量提前保存下一个节点的指针next


1、将下一个节点指针保存到next变量 next = curr.next

2、将下一个节点的指针指向prev,curr.next = prev

3、准备处理下一个节点,将curr赋值给prev

4、将下一个节点赋值为curr,处理一个节点

解法2:

递归:以相似的方法重复,类似于树结构,先从根节点找到叶子节点,从叶子节点开始遍历大的问题(整个链表反转)拆成性质相同的小问题(两个元素反转)curr.next.next = curr将所有的小问题解决,大问题即解决

只需每个元素都执行curr.next.next = curr,curr.next = null两个步骤即可为了保证链不断,必须从最后一个元素开始

public class ReverseList {
	static class ListNode{
		int val;
		ListNode next;
		public ListNode(int val, ListNode next) {
			this.val = val;
			this.next = next;
		}
	}
	public static ListNode iterate(ListNode head){
		ListNode prev = null,curr,next;
		curr = head;
		while(curr != null){
			next = curr.next;
			curr.next = prev;
			prev = curr;
			curr = next;
		}
		return prev;
	}
	public static ListNode recursion(ListNode head) {
		if (head == null || head.next == null) {
			return head;
		}
		ListNode newHead = recursion(head.next);
		head.next.next = head;
		head.next = null;
		return newHead;
	}
	public static void main(String[] args) {
		ListNode node5 = new ListNode(5,null);
		ListNode node4 = new ListNode(4,node5);
		ListNode node3 = new ListNode(3,node4);
		ListNode node2 = new ListNode(2,node3);
		ListNode node1 = new ListNode(1,node2);
		//ListNode node = iterate(node1); ListNode node_1 = recursion(node1); System.out.println(node_1); } }

案例实战,举一反三

有如下链表:

要求对链表进行反转,反转后的链表如下:

题目解析

反转链表,就是将链表中每一个节点的 next 引用指向其前驱节点。链表默认自带一个引用,这个引用指向了头节点,记为 n1。首先尝试将 n1 的 next 引用进行反转:

可以发现,① 的 next 引用指向了空,由于 ① 切断了指向 ② 的引用,导致 n1 无法移动到 ② 和 ③,此时可以再引入一个引用,记为 n2,n2 指向 ②:

对 ② 进行反转:

这时候 ③ 丢失了,是否可以复用现有的引用来访问到 ③ 呢,答案是不行的。 ② 的前驱节点需要通过 n1 来访问,此时需再引入一个新的引用 n3,来指向 ③:

对 ③ 进行反转:

这时候三节点链表就完成了反转,题目到这是否就分析结束了呢?再引入一个节点 ④,如图:

不难发现,④ 节点又丢失了。再思考,能否复用现有引用,来访问到 ④,光从上图的结果来看,是不行的,一旦一个节点完成了反转,其后继节点就丢失了,除非创建与链表节点数量一致的引用,每一个引用指向其中一个节点,然后按上述方式对每个节点完成反转。这种方式显然不够优雅,那能否在反转下一个节点之前,先将引用后移,再反转呢?

接下来我们尝试边反转,边移动引用。通过上述分析,反转链表至少要 3 个引用,可以得出移动的时机是在反转 ③ 的时候,我们在反转 ③ 之前,先后移引用,保证不丢失 ④:

然后反转 ③:

我们需要指定一个引用,专门用来反转节点 next 指向。显然指定中间引用 n2 是合适的,n1 指向着 n2 的前驱节点,n3 指向着 n2 的后继节点,这样可以既完成反转,又不会丢失后续的节点。因此,我们在反转 ③ 之后,继续后移引用,使得 n2 指向 ④,完成对 ④ 的反转:

这里将移动和反转做了合并,可以看到,现在整个链表已经完成了反转。

代码实现

现在,我们只需将上述的分析结果翻译成代码即可。经过分析可知,反转链表一共需要三个引用,为了清晰直观,依次记为 prev、node、next,node 用于反转节点 next 指针。每当完成一次反转,三个引用便整体向后移动一个节点。代码实现如下:

public static Node reverse(Node node) {
	if (node == null || node.next == null) {
		return node;
	}
	
	Node prev = null;
	Node next = node.next;
	
	//next 指向空时,只需再进行最后一次反转
	while (next != null) {
		
		//反转节点
		node.next = prev;
		
		//引用后移
		prev = node;
		node = next;
		next = next.next;
	
	}

	//反转最后一个节点
	node.next = prev;
	
	//返回反转后的链表头引用
	return node;
}

需要注意的是,当 next 引用指向空时,末尾最后一个节点还未反转,所以在循环外要再反转一次。

另外,这里必须将处理好的 node 引用在方法中返回出去,通过拿方法的返回值来获取反转后的链表。如果仍然使用传入的 node,会发现 node 只剩下一个节点。有如下测试代码:

//定义链表:1 -> 2 -> 3
Node node = new Node(1);
node.next = new Node(2);
node.next.next = new Node(3);

System.out.println("原始链表:");
show(node);

//反转链表
Node rNode = reverse(node);

System.out.println("反转后:");
show(node);
show(rNode);

结果如下:

原始链表:
[Node{num=1, next=2}, Node{num=2, next=3}, Node{num=3, next=}]
反转后:
[Node{num=1, next=}]
[Node{num=3, next=2}, Node{num=2, next=1}, Node{num=1, next=}]

这是因为在 Java 中传递的是值,而不是引用。反转后的图例如下:


在传递 node 时,是将 node 保存的内存地址复制了一份,传给了方法参数 node,方法中对 node 的移动,不会影响方法外的 node。

反转链表至此完成,在解决链表相关问题时,要时刻注意不能丢失节点,在修改节点 next 或者 prev 指针时,都要保证仍能访问到其他节点,如果发现无法复用现有引用,可以尝试新增引用。保证了这一点之后,剩下的就是按题目要求实现即可。

篇幅有限,其他内容就不在这里一一给大家解析了,整理不易,非常欢迎大家一起学习交流,喜欢文章记得关注我点赞哟,感谢支持!

该资料获取方式:关注+转发后,私信【】获取完整版算法合集!

相关推荐

RouterOS 端口映射 (远程桌面)

一款功能强大的路由器系统-软路由-RouterOS推荐一款路由器系统,头条有很多喜欢使用软路由伙伴可能有很多都不知道RouterOS这个路由系统是,RouterOS是由拉脱维亚MikroTik...

神经网络中的编码器 神经网络视频编码

神经网络算法-一文搞懂Transformer(总体架构&三种注意力层)本文将从Transformer的本质、Transformer的原理、Transformer的应用三个方面,带您一...

必备资料103个WindowsXP运行命令

Windows中CMD最全命令行CMD命令:开始->运行(或者Windows+R)->键入cmd或command(在命令行里可以看到系统版本、文件系统版本)CMD命令锦集1.gpedit...

固态硬盘无法格式化怎么办

Windows中固态硬盘无法格式化怎么办?固态硬盘(简称SSD)是一种数据存储设备,与传统机械硬盘相比,它在许多方面表现得更好。因此,越来越多的用户希望使用固态硬盘,但是当人们购买固态硬盘后准备将其格...

手机信令数据分析_手机信令数据分析过程代码

清华大学公共管理学院刘志林教授:探索手机信令数据在城市治理中的应用中国发展网讯日前,由中国人民大学首都发展与战略研究院(以下简称“首发院”)主办的首都大讲堂(第7期)暨地方治理工作坊第二期在京举办。...

python开发ping工具 ipad python开发工具

python之ping主机#coding=utf-8frompythonpingimportpingforiinrange,):ip=&#;.&#;+str(i)...

云容灾关键技术点简介_云容器技术

阿里云发布企业级云灾备解决方案:一键容灾、成本节省%5月日,阿里云对外发布了企业级云灾备解决方案。据介绍,此次发布的灾备解决方案来自阿里巴巴IT基础设施云化的灾备经验,完全省去灾备机房的建设规划,可大...

域名泛解析设置_域名解析包括泛域名解析

如何降低域名被恶意泛解析的风险买车用车不想被忽悠,就请关注缸微信号:kf12gang←长按可复制。我们每天将免费为您解答选车用车的相关问题。作者:QQ126058域名被恶意泛解析是域名安全最常见的问...

人人通云平台怎么注册 人人通云教学登录账号

世界那么大,她看到了:一个心理咨询师的十年心灵之旅来源:环球网“世界那么大,我想去看看。”十年前的那个春天,十个字的辞职信,戳中了无数国人的心,激起了无数个“诗和远方”的小梦想,被称为“史上最具情怀...

民用远程监控手机软件_民用远程监控手机软件下载

屏幕监控软件有哪些?3款好用的监控软件分享!管控摸鱼小case!作为企业管理者,我深知员工工作效率和信息安全的重要性。在日常管理中,我时常会遇到这样的难题:员工是否在认真工作?有没有利用公司资源做与工...

重量级!Maven史上最全教程,看了必懂

对8个MCP服务器框架的比较作者:FrankGoortani编译:小兰引言模型上下文协议(MCP)是一种新标准,用于以统一方式将AI助手(如LLM)与外部数据源和工具连接起来。自推出以来,各种框架已...

面试字节跳动,收到offer后我却拒绝了 ,给面试人的一些忠告!

面试字节跳动,我被面试官狂怼全过程!来源:https://www.zhihu.com/question//answer/人们都说,这个世界上有两种人注定单身,一种是太优秀的,另一种是太平凡的。我一听呀...

ps1手柄 python Ps1手柄真假

别再花冤枉钱!教你一分钟辨别“真假”超皮秒▌什么是超皮秒?皮秒激光,就是每个激光发射的脉冲持续时间(脉宽)达到皮秒级别的激光;1ps等于的负次方秒,超皮秒其实是一种商业名称,本质上也是皮秒激光设备,我...

路由器接交换机UPLINK还是

最全攻略!网络小白也能看懂的交换机连接方法号主:老杨丨年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部中午好,我的网工朋友。在网络设备的世界里,交换机是不可或缺的存在。不同的连接方法...

tempdb 清理 tempdb可以删除吗

无需改代码,提高SQLSERVER数据库性能的个最简单方法众所周知SQLSERVER是微软的数据库拳头产品,有着图形化友好界面、操作门槛低、部署难度小,一键式安装的特点,受到全球开发者及企业的青睐...

取消回复欢迎 发表评论: