leetcode LCR24反转单链表

反转单链表

题目描述

题目分析 

先来说迭代的思想:

上面next = cur->next应该放在cur->next = pre前面执行,这里笔误 

再来说递归的思想:

 题目代码

这个代码里面我加了我自己写的测试数据,自己可以去找对应的部分,直接粘贴赋值就可以在leetcode提交成功,我们就没有把迭代与递归单独分开了,里面还有大量的注释说明,请结合题目分析仔细观看

java版本

package com.pxx.test;import sun.awt.image.ImageWatched;class LinkList {private ListNode head;private int length;//长度//链表结点的一个定义static class ListNode {int value;ListNode next;//初始化一个结点public ListNode(int value) {this.value = value;this.next = null;}}public ListNode getHead() {return this.head;}//实现数据的尾插public void insertEnd(int value) {ListNode newNode = new ListNode(value);if (newNode != null) {if (head == null) {head = newNode;//指向第一个结点} else {ListNode cur = head;//移动到最后一个结点的位置while (cur.next != null) {cur = cur.next;}//最后一定是在cur加入结点cur.next = newNode;}length++;}}//打印public void printList(ListNode head) {ListNode cur = head;while (cur != null) {System.out.print(cur.value + " ");cur = cur.next;}System.out.println();}//利用递归反转链表//返回反转之后的链表头public ListNode reverse(ListNode head) {//安全检查都必须先进行操作if (head == null || head.next == null) {return head;} else {ListNode pre = head , cur = head.next;//接收最后一次的返回,就是最后一个节点,中间是没有结点要返回的//这里为什么传入pre.next,而不是cur.next//目的其实就是为了每一个值都能被链上,为什么那么说呢//1(pre) 2(cur) 3 4 5//如果按照cur.next来进行移动//1 <- 2这一部分递归了之后,就会进入 3(pre(cur会直接到3变成pre))   4(内部的cur)//那么我请问2 3中间这条线被狗吃了吗?所以以pre.next往下递归//上面pre循环到5号结点,也就是最后一组递归就要结束,因此有head.next = null就结束递归ListNode res = reverse(pre.next);cur.next = pre;//目的把第一个结点的next指向null//这里千万不能吧pre.next 与 cur.next进行比较//否则会造成最开头的两个数据一直轮替//这样来说 1  2  3  4(pre)  5(cur)假设当前指针是这样来指的//4 <- 5 此时4也还是4->5的,进入pre.next把指向变为了null(注意这是递归所以从后往前分析)//不太懂的请结合我的递归分析图来看//null <- 4 <- 5//那么就行往前递归3(pre) 4(cur) 5,也就是null <- 3 <- 4 <- 5//我们注意到一个问题就是4的pre已经在中间的时候被改向了第一个结点//那么对于1(pre) <- 2(cur)来说,1的.next又等于cur,所以1.pre = null//null <- 1 <- 2......这个时候,程序已经全部执行完if (pre.next == cur) {pre.next = null;}return res;}}//利用迭代思想实现public ListNode reverse1(ListNode head) {//空结点,直接返回一个nullif (head == null) {return null;}//定义三个指针进行迭代ListNode pre = head, cur = head.next, next;//next用于在中间轮替指针可以先不用初值//没循环之前先把第一个结点next指向nullhead.next = null;while (cur != null) {//这里迭代就是// null <- 1(pre) 2(cur) 3(next) 4        5// null <- 1 <-   2(pre) 3(cur)  4(next)  5// null <- 1 <-   2 <-   3(pre)  4(cur)   5(next)// null <- 1 <-   2 <-   3 <-    4(pre)   5(cur)   next(这个时候还会进入循环里面更改cur.next指针)//这个时候cur == null,结束,pre指向最后一个结点返回//保留next指向next = cur.next;//这一步必须放在cur.next前面,不然cur.next就被先改变了,next的位置就不对了cur.next = pre;//改变pre与curpre = cur;//这一步放在cur=next,这里就是先赋值pre,在改变curcur = next;}//最后一定是pre指向了最后一个结点return pre;}}public class Test4 {public static void main(String[] args) {LinkList linkList = new LinkList();//开始插入数据linkList.insertEnd(1);linkList.insertEnd(2);linkList.insertEnd(3);
//        linkList.insertEnd(4);
//        linkList.insertEnd(5);linkList.printList(linkList.getHead());//反转链表LinkList.ListNode head = linkList.reverse(linkList.getHead());linkList.printList(head);}
}

 c语言版本测试代码,仅做参考

#include <stdio.h>
#include <stdlib.h>// 链表结点的定义
struct ListNode {int value;struct ListNode* next;
};// 链表的定义
struct LinkedList {struct ListNode* head;int length;
};// 初始化链表
void initLinkedList(struct LinkedList* list) {list->head = NULL;list->length = 0;
}// 在链表末尾插入一个新节点
void insertEnd(struct LinkedList* list, int value) {struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode != NULL) {newNode->value = value;newNode->next = NULL;if (list->head == NULL) {list->head = newNode;} else {struct ListNode* cur = list->head;while (cur->next != NULL) {cur = cur->next;}cur->next = newNode;}list->length++;}
}// 打印链表的元素
void printList(struct ListNode* head) {struct ListNode* cur = head;while (cur != NULL) {printf("%d ", cur->value);cur = cur->next;}printf("\n");
}// 递归反转链表
struct ListNode* reverse(struct ListNode* head) {if (head == NULL || head->next == NULL) {return head;} else {struct ListNode* pre = head;struct ListNode* cur = head->next;struct ListNode* res = reverse(pre->next);cur->next = pre;if (pre->next == cur) {pre->next = NULL;}return res;}
}int main() {struct LinkedList linkList;initLinkedList(&linkList);// 开始插入数据insertEnd(&linkList, 1);insertEnd(&linkList, 2);insertEnd(&linkList, 3);printList(linkList.head);// 反转链表linkList.head = reverse(linkList.head);printList(linkList.head);return 0;
}

好了,祝早安,午安,晚安

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

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

相关文章

【Linux】Linux第一个小程序 --- 进度条

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和Linux还有算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 …

C++STL库常用详解与原理

CSTL库 学习方法&#xff1a;使用STL的三个境界&#xff1a;能用&#xff0c;明理&#xff0c;能扩展。 常用库 库名称所需头文件数据结构string#include<string>串vector#include<vector>动态数组list#include<list>带头双向循环链表queue#include<queu…

14.Tomcat和HTTP协议-[一篇通]

文章目录 1.HTTP 协议1.1HTTP 是什么1.2理解 "应用层协议"1.3理解 HTTP 协议的工作过程1.4HTTP 协议格式1.4.1抓包工具的使用(Fiddler)1.4.2抓包工具的原理1.4.3抓包结果1.4.4协议格式总结 1.5HTTP 请求 (Request)1.5.1认识 URL1.5.1.1URL 基本格式1.5.1.2关于 URL e…

小程序如何进行一键修复

在使用小程序过程中&#xff0c;难免会遇到一些问题&#xff0c;比如程序崩溃、功能异常等等。这时&#xff0c;版本一键修复就显得尤为重要了。下面&#xff0c;我们就来介绍一下小程序如何进行版本一键修复。 一、什么是版本一键修复&#xff1f; 版本一键修复是指在小程序…

算法训练 第九周

一、移动零 1.双指针 我们可以设定两个指针i和j&#xff0c;其中i用来遍历整个数组&#xff0c;j用来遍历存放不为零的数的位置&#xff0c;当nums[i]不等于零时&#xff0c;就让nums[i]和nums[j]进行交换&#xff0c;然后j,当我们遍历完整个数组之后就完成了操作&#xff0c;…

【数据库】基于散列的两趟算法原理,以及集合与包的并,差,交,连接操作实现原理,执行代价以及优化

基于散列的两趟算法 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定…

shiro整合redis

shiro整合redis 前言&#xff1a;shiro默认的session是存储在jvm内存中的&#xff0c;这样会导致java服务内存占用更大以及一旦服务器宕机或者版本迭代需要重启服务时&#xff0c;缓存中的数据不能恢复&#xff0c;导致用户需要重新登录认证&#xff0c;体验很差。因此利用第三…

JavaScript 表达式

JavaScript 表达式 目录 JavaScript 表达式 一、赋值表达式 二、算术表达式 三、布尔表达式 四、字符串表达式 表达式是一个语句的集合&#xff0c;计算结果是个单一值。 在JavaScript中&#xff0c;常见的表达式有4种&#xff1a; &#xff08;1&#xff09;赋值表达式…

CopyOnWriteArrayList源码解析

CopyOnWriteArrayList源码解析 文章目录 CopyOnWriteArrayList源码解析一、CopyOnWriteArrayList二、总结 一、CopyOnWriteArrayList 在 JUC 中&#xff0c;对于 ArrayList 的线程安全用法&#xff0c;比较推崇于使用 CopyOnWriteArrayList &#xff0c;那么CopyOnWriteArrayL…

前端 | iframe框架标签应用

文章目录 &#x1f4da;嵌入方式&#x1f4da;图表加载显示&#x1f4da;100%嵌入及滑动条问题&#x1f4da;加载动画保留 前情提要&#xff1a; 计划用iframe把画好的home1.html&#xff08;echarts各种图表组成的html数据大屏&#xff09;嵌入整合到index.html&#xff08;搭…

API接口测试工具的主要作用及选择指南

API接口测试是现代软件开发中至关重要的一环。为了确保不同组件之间的无缝集成和功能正常运作&#xff0c;API接口测试工具应运而生。本文将介绍API接口测试工具的主要作用&#xff0c;以及在选择适合项目的工具时需要考虑的因素。 1、功能测试&#xff1a;API接口测试工具的首…