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

【题目描述】

输入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≤b

    if(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个整数相不相等。所以,本题要考虑输入的三个数相等的情况。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3Dmax最全快捷键大全,赶紧收藏起来练习起来吧

3Dmax做为一款专业的建模软件&#xff0c;有很多快捷键能帮助我们更好地学习&#xff0c;提升自己的能力。 废话不多说&#xff0c;我们一起来看看。 以上就是3dmax最全快捷键大全&#xff0c;看着容易&#xff0c;但是想要掌握好还需要我们多多练习。 本地max跑图太慢的朋友可…

数据链路层----滑动窗口协议的相关计算

目录 1.窗口大小的相关计算 •停等协议&#xff1a; •后退N帧协议&#xff1a; •选择重传协议&#xff1a; 2.信道利用率相关计算 •停等协议的信道利用率&#xff1a; •连续ARQ&#xff08;后退N帧协议&#xff0c;选择重传协议&#xff09;的信道利用率&#xff1a;…

SAP PP学习笔记04 - BOM2 -通过Serial来做简单的BOM变式配置,副明细,BOM状态,BOM明细状态,项目种类,递归BOM

本章继续讲BOM。 本章讲通过Serial来做简单的BOM变式配置。还讲了BOM的相关概念&#xff1a;副明细&#xff0c;BOM状态&#xff0c;BOM明细状态&#xff0c;项目种类&#xff0c;递归BOM 等。 1&#xff0c;通过Serial&#xff08;序列号&#xff09;来做简单的 VC&#xff0…

软考信息系统项目管理师零基础怎么学习?

软考考信息系统项目管理师&#xff0c;零基础怎么入手高项&#xff1f; 要我说对于没有基础的人群来说零基础考信息系统项目管理师还是有一定的难度的&#xff0c;难就难在需要时间去了解基础&#xff0c;而相对于系统分析师、系统构架设计师、网络规划设计师、系统规划与管理…

C++多态详解

文章目录 多态概念定义及实现构成条件虚函数虚函数的重写override 和 final重载、覆盖、隐藏 抽象类纯虚函数接口继承与实现继承 多态的原理虚函数表原理动态绑定与静态绑定 多继承的虚函数表多继承中的虚函数表 多态 概念 多态是面向对象三大特性中相对复杂的一个&#xff0…

c语言网络编程学习整理 网络编程结构框架 一些常见协议的介绍

1.网络分层&#xff1a;osi体系结构 重点&#xff1a;网络层&#xff0c;传输层。 口诀&#xff1a;物数网传会表应。 可是osi体系过于理想&#xff0c;不过其为原型依旧通用&#xff1a; TCP/IP协议 是Internet事实上的工业标准 2.TCP/IP 4层模型 1&#xff09;网络接口与…

Java生成 word报告

Java生成 word报告 一、方案比较二、Apache POI 生成三、FreeMarker 生成 在网上找了好多天将数据库信息导出到 word 中的解决方案&#xff0c;现在将这几天的总结分享一下。总的来说&#xff0c;Java 导出 word 大致有 5 种。 一、方案比较 1. Jacob Jacob 是 Java-COM Bri…

7款炫酷的前端动画特效分享(三)(附效果图及在线演示)

分享7款好玩的前端动画特效 其中有CSS动画、SVG动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 CSS3模仿四季交替动画 基于HTML5CSS3实现的卡通风格一年四季交替动画特效 以下效果图只能体现框架的…

ThreadPoolExecutor 学习

ThreadPoolExecutor 是开发中最常用的线程池&#xff0c;今天来简单学习一下它的用法以及内部构造。 1、线程池存在的意义&#xff1f; 一般在jvm上&#xff0c;用户线程和操作系统内核线程是1&#xff1a;1的关系&#xff0c;也就是说&#xff0c;每次创建、销毁线程的时候&am…

10.WEB渗透测试-Linux基础知识-Linux用户权限管理(下)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;9.WEB渗透测试-Linux基础知识-Linux用户权限管理&#xff08;上&#xff09;-CSDN博客 ch…

Linux进程详细介绍

文章目录 Linux进程1、计算机体系结构和操作系统管理1.1、计算机体系结构 -- 硬件1.2、操作系统&#xff08;Operator System&#xff09; -- 软件 2、进程2.1、进程基本概念2.2、进程标识符2.2.1、获取当前进程标识符和当前进程的父进程标识符2.2.2、通过系统调用创建进程 -- …

微信小程序开发学习笔记《19》uni-app框架-配置小程序分包与轮播图跳转

微信小程序开发学习笔记《19》uni-app框架-配置小程序分包与轮播图跳转 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、配置小程序分包 分包可以减少小程序首次启动时的加载时间 为此&#…

Google Play上架:自查封号政策解析(高风险行为之不允许破坏Google Play生态系统中用户信任度的应用或应用内容)

本文章提供给近期被封号的开发者们&#xff0c;希望能带来帮助&#xff0c;有其他的自查方向后续也会发布出来。 ——————————————————————————————————————— 用户数据设备和网络滥用 用户数据 设备和网络滥用

前端学习之HTML(第二天)--多媒体标签和表格标签

注&#xff1a;里面的注释是对各个标签的解释 多媒体标签 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title></title> </head> <body> <!-- audio是音频可以填写绝对路径也可填写相对路径 --> &l…

解决微软活动目录管理工作中常见问题

微软活动目录&#xff08;AD域&#xff09;是一种由微软的用于管理网络中用户、计算机、资源等的目录服务。活动目录被广泛应用于企业内部的网络管理中&#xff0c;尤其是对于使用微软产品的企业来说&#xff0c;活动目录是至关重要的基础设施之一。 因此&#xff0c;以微软为…

索引下推 INDEX CONDITION PUSHDOWN

索引下推 (INDEX CONDITION PUSHDOWN&#xff0c;简称ICP)是在 MySQL5.6 针对扫描索引下推二级索引的一项优化改进。 用来在范围查询时减少回表的次数。ICP适用于 MYISAM和INNODB.

ref和reactive用哪个?

ref和reactive用哪个? 1.&#x1f916;GPT&#x1f916;:ref和reactive用哪个根据数据类型而定 ref 用于将基本类型的数据&#xff08;如字符串、数字&#xff0c;布尔值等&#xff09;转换为响应式数据。使用 ref 定义的数据可以通过 .value 属性访问和修改。 reactive 用于…

JavaScript 学习笔记(7)

一模板字符串 1.用途 允许在字符串中嵌入表达式和变量&#xff0c;是一种方便的字符串语法 2.用法 模板字符串使用反引号 作为字符串的定界符分隔的字面量&#xff1b;模板字面量是用反引号&#xff08;&#xff09;分隔的字面量&#xff0c;允许多行字符串、带嵌入表达式…

ElasticSearch之分布式查询过程分析

写在前面 本文一起看下es分布式查询的过程。 1&#xff1a;分布式搜索过程 分布式搜索分为两个阶段&#xff0c;query和fetch,即query-then-fetch。 假定primary shard3,replica shard1&#xff0c;即3个主分片&#xff0c;1个副本分片。 1.1&#xff1a;query阶段 某data …

二叉树——700. 二叉搜索树中的搜索、98. 验证二叉搜索树

二叉搜索树中的搜索 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和一个整数值 val。 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 null 。 示例 1: 输入&#xff1a;root [4,2,7,1,3], val 2 …