三整数排序问题的解题逻辑

【题目描述】

输入3个整数,从小到大排序后输出。

【样例输入】

20 7 33

【样例输出】

7 20 33

【解析】

本题解法大概有3种:

1、穷举条件法。

此方法先判断a、b、c大小的所有可能,再根据各种可能性输出不同的排序。

思路是先判断a、b的大小,此时可把a、b想象成一个数轴上的两个点,即将数轴分成3个部分,然后再判断c在这3个部分中的哪一段,由此实现排序输出。

这种方法是正向法,对条件的穷举比较费脑细胞,不够简单明了。

#include<stdio.h>int main(){int a, b, c;scanf("%d%d%d", &a, &b, &c);if(a<b){if(c<a){printf("%d %d %d", c, a, b);}else if(c>b){printf("%d %d %d",a, b, c);}else{printf("%d %d %d",a, c, b);}}else{if(c<b){printf("%d %d %d", c, b, a);}else if(c>a){printf("%d %d %d",b, a, c);}else{printf("%d %d %d",b, c, a);}}return 0;}

2、排列法(最简单的方法)

这种方法属于逆向思维法,其好处是由结果反推条件,能够避开复杂的逻辑判断。

abc三个数的全排列有6种:abc、acb、bac、bca、cab、cba,所以最简单的方法就是直接用if判断这6种输出对应的条件。

#include<stdio.h>int main(){int a, b, c;scanf("%d%d%d", &a, &b, &c);if(a < b && b < c)printf("%d %d %d\n", a, b, c);if(a < c && c < b)printf("%d %d %d\n", a, c, b);if(b < a && a < c)printf("%d %d %d\n", b, a, c);if(b < c && c < a)printf("%d %d %d\n", b, c, a);if(c < a && a < b)printf("%d %d %d\n", c, a, b);if(c < b && b < a)printf("%d %d %d\n", c, b, a);return 0;}

上述程序看上去没有错误,而且能通过题目中给出的样例,但可惜有缺陷:输入“111”将得不到任何输出!

这个例子说明:样例输出正确不代表程序正确。因为程序要满足对任意符合要求的输入均得到正确的结果,而不仅是样例数据。

上面的问题在于,忽略了输入数据相等的情况。上述6种排列的充分必要条件为:a≤b≤c、a≤c≤b、b≤a≤c、b≤c≤a、c≤a≤b、c≤b≤a。

那把所有的 “<”改成“<=”总可以了吧?很遗憾,还是不行。对于“111”,6种情况全部符合,程序会输出6次“111”。

解决方案是把所有的if改成else if,这样就可以让程序自动排除交叉情况。下面是优化后的最终代码:

#include<stdio.h>int main(){int a, b, c;scanf("%d%d%d", &a, &b, &c);if(a <= b && b <= c) printf("%d %d %d\n", a, b, c);else if(a <= c && c <= b) printf("%d %d %d\n", a, c, b);else if(b <= a && a <= c) printf("%d %d %d\n", b, a, c);else if(b <= c && c <= a) printf("%d %d %d\n", b, c, a);else if(c <= a && a <= b) printf("%d %d %d\n", c, a, b);else if(c <= b && b <= a) printf("%d %d %d\n", c, b, a);return 0;}

注:最后一条else if还可以简化成单独的else。

英语单词else表示“其他”,也就是“除此之外”、“否则”。比如一个妹子说:if(你爱我) 我就给你生儿子; else 我就死在你面前;

可见,起到排除交叉作用的正是这个else。

有些人称else if为语句,这是错误的,它们并不共同构成一个独立的语句。因else if虽然写在一起,但它们的关系并没有想象中的那么亲密无间。上面的代码本质上只是一个if…else语句的嵌套。

比如,下面这样一组语句:

if(...) ...;else if(...) ...;else if(...) ...;

它的真实面目是这样的:

if(...) ...;else {if(...) ...;else {if(...) ...;}}

只不过后一种写法有些麻烦,故而把else if凑在一起实现了代码形式上的简洁。

总之,有了else就能让编译器为我们排除条件交叉的情况,从而大大简化逻辑判断。

如果本题只用不含else的if语句,大家就能体会到其逻辑判断有多复杂。

不用else,就要人为设置好所有条件,做到“不重不漏”,这样的条件一共有多少种呢?

如果三整数不相等,那么这道题就简单了,本算法中第一段代码就是正解。

但是如果考虑到等号就比较复杂了,所以本题的关键就是判断输入数据相等的情况。

可以根“相等”的情况将本题的条件分类:

①三个数都不相等;

②有两个数相等;

③三个数都相等。

第①种情况刚才已经讨论过了,第③种情况也很简单(即a=b=c),关键是第②种情况。

第②种情况又可分为三种情形:ab相等、bc相等 、ac相等。

当ab相等时,与c比较又分为两种情形:ab小于c,ab大于c。据此上面三种情形又可细分为6种条件:

a) ab相等时分为两种情形:a=b<c,a=b>c;

b) bc相等时分为两种情形:b=c<a,b=c>a;

c) ac相等时分为两种情形:a=c<b,a=c>b;

综上,本题要判断的条件一共有13种:

①三个数都不相等:6种;

②有两个数相等:6种;

③三个数都相等:1种;

这就是人为判断条件的复杂程度,代码如下:

#include<stdio.h>int main(){int a, b, c;scanf("%d%d%d", &a, &b, &c);//三个数都不相等的6种条件if(a < b && b < c)printf("%d %d %d\n", a, b, c);if(a < c && c < b)printf("%d %d %d\n", a, c, b);if(b < a && a < c)printf("%d %d %d\n", b, a, c);if(b < c && c < a)printf("%d %d %d\n", b, c, a);if(c < a && a < b)printf("%d %d %d\n", c, a, b);if(c < b && b < a)printf("%d %d %d\n", c, b, a);//两个数相等的6种条件if(a == b && b < c)printf("%d %d %d\n", a, b, c);if(a == b && b > c)printf("%d %d %d\n", c, a, b);if(b == c && c < a)printf("%d %d %d\n", b, c, a);if(b == c && c > a)printf("%d %d %d\n", a, b, c);if(a == c && c < b)printf("%d %d %d\n", a, c, b);if(a == c && c > b)printf("%d %d %d\n", b, a, c);//三个数都相等的1种条件if(a == b && b == c)printf("%d %d %d\n", a, b, c);return 0;}

这段代码虽然条件很多,但好在理解起来容易。

能不能减少一下判断条件的数量呢,可以的,但是就需要更复杂的逻辑判断,理解起来也更复杂。

思路就是把“两个数相等的6种条件”与“三个数都不相等的6种条件”合并判断,更确切地说是把前者“插入”到后者。

后者表达式中所有的符号都是“<”,所以问题就变成了在后者的表达式中加“=”。

这里面需要注意:合并后的每个条件表达式只能含有一个等号。换句话说,“两个数相等的6种条件”中的每个条件只能与“三个数都不相等的6种条件”中唯一的一个条件合并,6种条件要一一对应。

因为一旦含有两个等号,就会出现重复条件判断。

比如a <= b < c可以分解为:a <b < c,a <=b < c。

而a <= b < =c却会分解为:a <b < c,a <b = c,a=b < c,a=b=c。

如果把要加等号的条件以“&&”为线分为左右两部分,则两侧都不能出现相同的等式,如下图:

总结起来规则有两条:

①每个if条件中只能有一个“=”;

②&&左右两侧都不能出现相同的等式。

假设在第一个条件中的a <b && b < c左侧加入等号,即变成a <=b && b < c,则可以依照上面两条规则从此等号开始按下图路线推出所有要加“=”的地方。

加入“=”后的代码如下:

#include<stdio.h>int main(){int a, b, c;scanf("%d%d%d", &a, &b, &c);//三个数都不相等+两个数相等的6种条件if(a <= b && b < c)printf("%d %d %d\n", a, b, c);if(a < c && c <= b)printf("%d %d %d\n", a, c, b);if(b < a && a <= c)printf("%d %d %d\n", b, a, c);if(b <= c && c < a)printf("%d %d %d\n", b, c, a);if(c <= a && a < b)printf("%d %d %d\n", c, a, b);if(c < b && b <= a)printf("%d %d %d\n", c, b, a);//三个数都相等的1种条件if(a == b && b == c)printf("%d %d %d\n", a, b, c);return 0;}

前面讲过,a <= b < =c分解为:a <b < c,a <b = c,a=b < c,a=b=c,所以可以将代码进一步合并:

#include<stdio.h>int main(){int a, b, c;scanf("%d%d%d", &a, &b, &c);//三个数都不相等+两个数相等+三个数都相等的6种条件if(a <= b && b <= c)printf("%d %d %d\n", a, b, c);if(a < c && c < b)printf("%d %d %d\n", a, c, b);if(b < a && a <= c)printf("%d %d %d\n", b, a, c);if(b <= c && c < a)printf("%d %d %d\n", b, c, a);if(c <= a && a < b)printf("%d %d %d\n", c, a, b);if(c < b && b <= a)printf("%d %d %d\n", c, b, a);return 0;}

这就是不含else的最精简的代码。

之所以弄这么一大通,就是为了让客官体验一下没有else的帮助编写代码将会多么的复杂,而且一不小心等号加错了位置就会前功尽弃。有了else就完全避免了以上复杂的逻辑分析,还不容易出错,真的是又快又准。

3、交换变量排序法:还有一种思路是把a、b、c这3个变量本身改成a≤b≤c的形式。步骤如下:

1)通过交换变量让a变成3个数的最小值。首先让a分别与b、c比较,如果a>b、c,则交换a和b、c(利用前面讲过的三变量交换法),从而保证a≤c,且a≤b,也就是将a变成3个数的最小值。

2)通过交换变量让b变成b、c中的最小值。检查b和c,如果b>c,交换b、c。

#include<stdio.h>int main(){int a, b, c, t;scanf("%d%d%d", &a, &b, &c);if(a > b) { t = a; a = b; b = t; } //执行完毕之后a≤bif(a > c) { t = a; a = c; c = t; } //执行完毕之后a≤c,且a≤b依然成立if(b > c) { t = b; b = c; c = t; }printf("%d %d %d\n", a, b, c);return 0;}

总结:本题需要注意的是输入限定条件——3个整数。也就是说只要满足3个整数即可,没限定这3个整数相不相等。所以,本题要考虑输入的三个数相等的情况。

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

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

相关文章

C++17中的类模板参数推导

在C17之前&#xff0c;必须明确指出类模板的所有参数。自从C17起必须指明类模板参数的限制被放宽了。通过使用类模板参数推导(Class Template Argument Deduction(CTAD))&#xff0c;只要编译器能根据初始值推导出所有模板参数&#xff0c;那么就可以不指明参数。 C17中的类模板…

记录一次排查负载均衡不能创建的排查过程

故障现象&#xff0c;某云上&#xff0c;运维同事在创建负载均衡的时候&#xff0c;发现可以创建资源&#xff0c;但是创建完之后&#xff0c;不显示对应的负载均衡。 创建负载均衡时候&#xff0c;按f12发现console有如下报错 后来请后端网络同事排查日志发现&#xff0c;是后…

中科大计网学习记录笔记(十七):拥塞控制原理 | TCP 拥塞控制

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

论文学习—Model-based Adversarial Meta-Reinforcement Learning

Model-based Adversarial Meta-Reinforcement Learning Abstract1. Introduction2. Related work3 Preliminaries基于模型的强化学习&#xff08;MBRL&#xff09;:区别和联系&#xff1a; 4 Model-based Adversarial Meta-Reinforcement Learning4.1 Formulation 4.2 Computin…

LeetCode 每日一题 Day 88 - 94

2673. 使二叉树所有路径值相等的最小代价 给你一个整数 n 表示一棵 满二叉树 里面节点的数目&#xff0c;节点编号从 1 到 n 。根节点编号为 1 &#xff0c;树中每个非叶子节点 i 都有两个孩子&#xff0c;分别是左孩子 2 * i 和右孩子 2 * i 1 。 树中每个节点都有一个值&a…

好书推荐丨细说PyTorch深度学习:理论、算法、模型与编程实现

文章目录 写在前面深度学习推荐图书内容简介作者简介 推荐理由粉丝福利写在最后 写在前面 本期博主给大家推荐一本深度学习的全新正版书籍&#xff0c;感兴趣的小伙伴快来看看吧~ 深度学习 深度学习是机器学习的一个分支&#xff0c;它模仿人脑神经网络的工作原理进行复杂的…

蓝桥杯练习系统(算法训练)ALGO-986 藏匿的刺客

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 强大的kAc建立了强大的帝国&#xff0c;但人民深受其学霸及23文化的压迫&#xff0c;于是勇敢的鹏决心反抗。   kAc帝国防…

linux kernel物理内存概述(二)

目录 物理内存数据结构 设备数物理内存描述 物理内存映射 map_kernel map_mem zone数据结构 zone类型 物理内存数据结构 站在处理器角度&#xff0c;管理物理内存的最小单位是页面。使用page数据结构描述&#xff0c;通常默认大小4kB&#xff0c;采用mem_map[]数组来存…

学习java第一天(下载并配置环境+写第一个java程序)

一.安装 1.下载 直接去官网上选择与你电脑符合的版本下载 官网链接Java Archive Downloads - Java SE 8u211 and later &#xff08;拿我的为例 Windows x64版本&#xff09; ​ 2.然后安装好exe&#xff08;要让自己知道在哪&#xff09; 3.配置环境 大佬链接&#xff1…

“每一次的感应,都是对环境的温柔拥抱。”#STM32项目二 《感应开关盖垃圾桶》【上】

“每一次的感应&#xff0c;都是对环境的温柔拥抱。”#STM32项目二 《感应开关盖垃圾桶》【上】 前言预备知识1.定时器介绍11.1软件延时的优缺点1.2定时器工作原理1.3定时器的分类1.4 STM32F103C8T6定时器资源1.5通用定时器介绍 2.定时器介绍22.1定时器计数模式2.2定时器时钟源…

【VTKExamples::PolyData】第四十六期 Reflection

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例Reflection,并解析接口vtkReflectionFilter,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. Reflection …

Docker容器详解

一、概述 1.1 基本概念&#xff1a; Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚…

SpringCloud 各自组件的停更/升级/替换

一、停更不停用 现在 SpringCloud 不再修复 bug&#xff0c;也不再接收合并请求&#xff0c;也不再发布新版本&#xff0c;但是目前还是可以继续使用的。 二、以前的组件 以前 SpringCloud 常用的组件如下图&#xff0c;服务的注册和发现使用 Eureka&#xff0c;服务的负载和调…

深入理解c指针(七)

目录 十、回调函数和qsort函数 1、回调函数 2、简单介绍size_t 数据类型 3、qsort 排序函数 3.1 qsort函数简单举例1&#xff08;升序排序&#xff09; 3.2 qsort函数简单举例2&#xff08;字符串长度排序&#xff09; 3.3 简单讲解 -> 操作符 3.4 常见符号的ASCII…

如何利用会话式AI提升你的工作效率?

会话式AI如何改变我们的生活和工作 在当今时代&#xff0c;内容策略的重要性日渐凸显&#xff0c;良好的内容策略能够与流量及转化率紧密相连&#xff0c;成为企业在内容策略领域不容忽视的营销工具之一。 然而&#xff0c;目前内容同质化现象严重&#xff0c;企业若想在内容营…

iPaas数据传输的方式

一、iPaas平台概述 iPaas&#xff08;Integration Platform as a Service&#xff09;平台&#xff0c;作为一种先进的云计算服务模式&#xff0c;为开发者和企业提供了一种全面且灵活的应用集成解决方案。它构建在PaaS&#xff08;Platform as a Service&#xff09;基础之上…

【C++庖丁解牛】初始化列表 | Static对象 | 友元函数

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1. 再谈构造函数1.1 …

WiFi模块赋能智能手表:拓展功能与提升连接性

随着科技的不断进步&#xff0c;智能手表正逐渐成为现代人生活中不可或缺的智能配饰。其中&#xff0c;WiFi模块的应用为智能手表带来了更多强大的功能和更高的连接性&#xff0c;为用户提供了更为便捷、智能化的使用体验。本文将深入探讨WiFi模块在智能手表中的应用。 远程通信…

RK DVP NVP6158配置 学习

NVP6158简介 NVP6158C是一款4通道通用RX&#xff0c;提供高质量图像的芯片。它接受来自摄像机和其他视频信号的独立4通道通用输入来源。它将4通道通用1M至8M 7.5P视频格式数字化并解码为代表8位ITU-R BT.656/1120 4:2:2格式的数字分量视频&#xff0c;并将单独的BT.601格式与27…

40个Python字符串实例

Python 字符串是 Python 编程语言中最常用的数据类型之一&#xff0c;它可以表示文本或一组字符。Python 中的字符串是不可变的序列&#xff0c;意味着一旦创建&#xff0c;其值就不能被修改。下面是一些关于 Python 字符串的介绍。 概述 创建字符串&#xff1a;可以使用单引…