每日一题-单链表排序
为了对给定的单链表按升序排序,我们可以考虑以下解决方法:
思路
-
归并排序(Merge Sort):由于归并排序的时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),并且归并排序不需要额外的空间(空间复杂度为 O ( 1 ) O(1) O(1),但实际上需要递归栈空间),这使得它非常适合用来排序链表。通过归并排序对链表进行排序时,节点的值会被有效地排序,同时还保证了时间和空间的复杂度要求。
-
链表操作:我们需要将链表分割为两个子链表,递归地对这两个子链表进行排序,然后合并它们。
步骤
- 分割链表:通过快慢指针的方法找到链表的中间节点,将链表分为两部分。
- 递归排序:递归地对每一部分链表进行排序。
- 合并排序后的链表:将两个已排序的链表合并成一个有序链表。
代码实现
struct ListNode {int val;struct ListNode* next;
};/*** 合并两个已经排序的链表*/
#include <stdio.h>
#include <stdlib.h>struct ListNode {int val;struct ListNode* next;
};/*** 合并两个已经排序的链表*/
struct ListNode* merge(struct ListNode* left, struct ListNode* right) {struct ListNode dummy;struct ListNode* p = &dummy;// 合并两个链表while (left != NULL && right != NULL) {if (left->val < right->val) {p->next = left;left = left->next;} else {p->next = right;right = right->next;}p = p->next;}// 如果还有剩余的元素,直接连接到结果链表if (left != NULL) {p->next = left;} else {p->next = right;}return dummy.next;
}/*** 找到链表的中间节点*/
struct ListNode* findMid(struct ListNode* head) {// 添加空指针检查if (head == NULL || head->next == NULL) {return head;}struct ListNode* slow = head;struct ListNode* fast = head->next; // Changed initial position// 快慢指针找到中点while (fast != NULL && fast->next != NULL) {slow = slow->next;fast = fast->next->next;}return slow;
}/*** 归并排序链表*/
struct ListNode* sortInList(struct ListNode* head) {// 如果链表为空或只有一个元素,直接返回if (head == NULL || head->next == NULL)return head;// 找到链表的中间节点struct ListNode* mid = findMid(head);struct ListNode* right = mid->next;mid->next = NULL; // 分割链表为两部分struct ListNode* left = head;// 递归排序两个子链表left = sortInList(left);right = sortInList(right);// 合并两个排序后的链表return merge(left, right);
}int main() { // Changed from void main() to int main()// 创建链表: 1 -> 2 -> 3 -> 4 -> 5struct ListNode* pHead1 = (struct ListNode*)malloc(sizeof(struct ListNode));pHead1->val = 1;pHead1->next = (struct ListNode*)malloc(sizeof(struct ListNode));pHead1->next->val = 2;pHead1->next->next = (struct ListNode*)malloc(sizeof(struct ListNode));pHead1->next->next->val = 3;pHead1->next->next->next = (struct ListNode*)malloc(sizeof(struct ListNode));pHead1->next->next->next->val = 4;pHead1->next->next->next->next = (struct ListNode*)malloc(sizeof(struct ListNode));pHead1->next->next->next->next->val = 5;pHead1->next->next->next->next->next = NULL;// 排序链表struct ListNode* result = sortInList(pHead1);// 打印排序后的链表struct ListNode* cur = result;while (cur != NULL) {printf("%d -> ", cur->val);cur = cur->next;}printf("NULL\n");// 释放内存while (result != NULL) {struct ListNode* temp = result;result = result->next;free(temp);}return 0;
}
补充:选择 dummy.next 或 dummy->next
在代码中,dummy.next 和 dummy->next 之间的区别取决于你使用的指针类型和编程语言的语法。
区别
-
dummy.next:这种写法通常用于在结构体中定义成员变量的情况,这种写法适用于对象实例而非指针类型。例如:struct ListNode {int val;ListNode* next; // 这是一个指针成员变量 };ListNode dummy; dummy.next = someNode; // 直接访问dummy对象的next成员 -
dummy->next:这种写法通常用于通过指针访问结构体的成员。在这种情况下,dummy是指向结构体的指针,你需要使用箭头操作符->来访问结构体的成员变量。例如:ListNode* dummy = new ListNode(); dummy->next = someNode; // 使用箭头符号来访问指针dummy的next成员
选择 dummy.next 或 dummy->next
dummy.next是用在我们直接创建一个结构体对象时(即没有使用指针),通过对象访问其成员变量。dummy->next是用在我们使用结构体指针时,通过指针来访问结构体的成员变量。
代码中的具体情况
在你的归并排序代码中,dummy 是一个结构体对象而不是指针,所以我们使用 dummy.next 来访问结构体成员 next。而如果我们把 dummy 定义为一个指针(即 ListNode* dummy = new ListNode();),那么就应该使用 dummy->next 来访问成员变量。
举个例子
使用结构体对象时:
ListNode dummy;
dummy.next = someNode; // 直接通过对象访问
使用结构体指针时:
ListNode* dummy = new ListNode();
dummy->next = someNode; // 使用箭头符号访问成员
总结
dummy.next:适用于dummy是结构体对象的情况。dummy->next:适用于dummy是结构体指针的情况。
还是挺好理解的,如果定义的是一个结构体,用.,如果定义的是一个结构体指针,用的是->。
解释
merge函数:将两个已排序的链表合并成一个排序好的链表。我们通过逐个比较节点的值来合并。findMiddle函数:使用快慢指针来找到链表的中间节点。快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针刚好到达中间位置。sortInList函数:这是主要的排序函数,利用归并排序的思想。首先通过findMiddle找到中间节点,将链表分为两部分,然后递归地对每一部分链表进行排序,最后用merge将排序后的两部分合并。
时间复杂度
- 归并排序的时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),其中 n n n 是链表的节点数。
- 每次递归分割链表的时间复杂度为 O ( n ) O(n) O(n),总共递归的层数为 O ( log n ) O(\log n) O(logn),因此总的时间复杂度为 O ( n log n ) O(n \log n) O(nlogn)。
空间复杂度
- 归并排序的空间复杂度为 O ( n ) O(n) O(n),因为递归栈的空间复杂度是 O ( log n ) O(\log n) O(logn),但每次合并需要额外的空间来存储结果链表。
相关文章:
每日一题-单链表排序
为了对给定的单链表按升序排序,我们可以考虑以下解决方法: 思路 归并排序(Merge Sort):由于归并排序的时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),并且归并排序不需要额外的空间(空…...
webpack04服务器配置
webpack配置 entryoutput filenamepathpublicPath 。。 打包引入的基本路径,,,比如引入一个bundle.js,。引用之后的路径就是 publicPathfilename -devServer:static : 静态文件的位置。。。hostportopencompress : 静态资源是否用gzip压缩hi…...
JDK下载安装配置
一.JDK安装配置。 1.安装注意路径,其他直接下一步。 2.配置。 下接第4步. 或者 代码复制: JAVA_HOME D:\Program Files\Java\jdk1.8.0_91 %JAVA_HOME%\bin 或者直接配置 D:\Program Files\Java\jdk1.8.0_91\bin 3.验证(CMD)。 java javac java -version javac -version 二.下…...
30_Redis哨兵模式
在Redis主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性…...
NLP三大特征抽取器:CNN、RNN与Transformer全面解析
引言 自然语言处理(NLP)领域的快速发展离不开深度学习技术的推动。随着应用需求的不断增加,如何高效地从文本中抽取特征成为NLP研究中的核心问题。深度学习中三大主要特征抽取器——卷积神经网络(Convolutional Neural Network, …...
《使用 YOLOV8 和 KerasCV 进行高效目标检测》
《使用 YOLOV8 和 KerasCV 进行高效目标检测》 作者:Gitesh Chawda创建日期:2023/06/26最后修改时间:2023/06/26描述:使用 KerasCV 训练自定义 YOLOV8 对象检测模型。 (i) 此示例使用 Keras 2 在 Colab 中…...
从MySQL迁移到PostgreSQL的完整指南
1.引言 在现代数据库管理中,选择合适的数据库系统对业务的成功至关重要。随着企业数据量的增长和对性能要求的提高,许多公司开始考虑从MySQL迁移到PostgreSQL。这一迁移的主要原因包括以下几个方面: 1.1 性能和扩展性 PostgreSQL以其高性能…...
服务器一次性部署One API + ChatGPT-Next-Web
服务器一次性部署One API ChatGPT-Next-Web One API ChatGPT-Next-Web 介绍One APIChatGPT-Next-Web docker-compose 部署One API ChatGPT-Next-WebOpen API docker-compose 配置ChatGPT-Next-Web docker-compose 配置docker-compose 启动容器 后续配置 同步发布在个人笔记服…...
51单片机 和 STM32 的烧录方式和通信协议的区别
51单片机 和 STM32 的烧录方式和通信协议的区别 1. 为什么51单片机需要额外的软件(如ISP)? (1)51单片机的烧录方式 ISP(In-System Programming): 51单片机通常通过 串口(…...
(STM32笔记)十二、DMA的基础知识与用法 第二部分
我用的是正点的STM32F103来进行学习,板子和教程是野火的指南者。 之后的这个系列笔记开头未标明的话,用的也是这个板子和教程。 DMA的基础知识与用法 二、DMA传输设置1、数据来源与数据去向外设到存储器存储器到外设存储器到存储器 2、每次传输大小3、传…...
【优选算法篇】:模拟算法的力量--解决复杂问题的新视角
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:优选算法篇–CSDN博客 文章目录 一.模拟算法二.例题1.替换所有的问号2.提莫攻击3.外观数列4…...
探秘 JMeter (Interleave Controller)交错控制器:解锁性能测试的隐藏密码
嘿,小伙伴们!今天咱们要把 JMeter 里超厉害的 Interleave Controller(交错控制器)研究个透,让你从新手直接进阶成高手,轻松拿捏各种性能测试难题! 一、Interleave Controller 深度剖析 所属家族…...
脚本化挂在物理盘、nfs、yum、pg数据库、nginx(已上传脚本)
文章目录 前言一、什么是脚本化安装二、使用步骤1.物理磁盘脚本挂载(离线)2.yum脚本化安装(离线)3.nfs脚本化安装(离线)4.pg数据库脚本化安装(离线)5.nginx脚本化安装(离…...
ESP嵌入式开发环境安装
前期准备,虚拟机,ios镜像,VSCode。 centOS8:centos安装包下载_开源镜像站-阿里云 虚拟机:vmware VSCode:Visual Studio Code - Code Editing. Redefined 如何安装镜像自行查找 完成以上环境后进行一下操…...
Elasticsearch入门学习
Elasticsearch是什么 Elasticsearch 是一个基于 Apache Lucene 构建的分布式搜索和分析引擎、可扩展的数据存储和矢量数据库。 它针对生产规模工作负载的速度和相关性进行了优化。 使用 Elasticsearch 近乎实时地搜索、索引、存储和分析各种形状和大小的数据。 特点 分布式&a…...
黑马linux笔记(03)在Linux上部署各类软件 MySQL5.7/8.0 Tomcat(JDK) Nginx RabbitMQ
文章目录 实战章节:在Linux上部署各类软件tar -zxvf各个选项的含义 为什么学习各类软件在Linux上的部署 一 MySQL数据库管理系统安装部署【简单】MySQL5.7版本在CentOS系统安装MySQL8.0版本在CentOS系统安装MySQL5.7版本在Ubuntu(WSL环境)系统…...
《软硬协同优化,解锁鸿蒙系统AI应用性能新高度》
在当今数字化时代,鸿蒙系统与人工智能的融合正逐渐成为科技领域的热门话题。如何通过软件和硬件协同优化,进一步提升鸿蒙系统中AI应用的整体性能,成为了开发者和技术爱好者们关注的焦点。 鸿蒙系统与AI应用的融合现状 鸿蒙系统以其独特的微…...
利用 Tree Shaking 提升 React.js 性能
Tree Shaking 是现代 JavaScript 应用中不可或缺的优化技术,它通过移除未使用的代码来减少最终打包的大小。对于 React.js 应用,这一技术尤为重要,因为随着组件和第三方库的增多,打包体积可能迅速膨胀。Tree Shaking 能显著提升加…...
RPC实现原理,怎么跟调用本地一样
回答1 要让⽹络通信细节对使⽤者透明,我们需要对通信细节进⾏封装,我们先看下⼀个 RPC 调⽤的流程涉及到哪些通 信细节: 1. 服务消费⽅( client )调⽤以本地调⽤⽅式调⽤服务; 2. client stub 接收到调…...
Vue进阶之AI智能助手项目(二)——ChatGPT的调用和开发
AI智能助手项目 service服务端文件目录src目录详解src/index.tschatGPT:src/chatgpt/index.ts前端接口部分src/api/index.tssrc/utils/request/index.tspost方法httpHttpOptionsrc/utils/request/axios.tsLayout布局页面-viewsexception异常页面src/views/exception/404/index…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
