1 条题解
-
0
三位数排序
一个自然的想法,和它的代价
三个数从小到大输出。第一反应可能是枚举:三个数的大小关系一共 3 × 2 × 1 = 6 种,逐种写 if 输出。写是能写对,但 6 个分支又长又容易漏,而且数一多(比如四个数)就是 24 种,此路不通。
突破口:排序就是"交换"
换个思路:不关心原来谁大谁小,只关心最终 a ≤ b ≤ c。那只要保证任意两个位置上的数都是小的在前——两两比较,逆序就交换,做三轮:
- a 和 b 比,把小的放 a
- a 和 c 比,把小的放 a
- b 和 c 比,把小的放 b
三轮做完,a、b、c 天然有序。这就是排序算法里最朴素的"冒泡"思想——现在还不需要数组,三个变量就够了。交换两个变量需要一个临时变量 t,这是第一次接触,记住这个三行套路。
代码实现
#include <stdio.h> int main() { int a, b, c, t; scanf("%d%d%d", &a, &b, &c); /* 两两比较,逆序则交换,保证 a <= b <= c */ if (a > b) { t = a; a = b; b = t; } if (a > c) { t = a; a = c; c = t; } if (b > c) { t = b; b = c; c = t; } printf("%d %d %d\n", a, b, c); return 0; }用样例验证:
1 14 5→ 第一轮交换成 1 14 5(a<b 不动),第二轮 a=1 < c 不动,第三轮 b=14 > c=5 交换 → 1 5 14 ✓;2 2 2三个 if 都不触发,原样输出 ✓。解法二:三目运算符
C 语言还有一个单行条件判断工具——三目运算符
条件 ? 值1 : 值2:条件成立取前者的值,不成立取后者。用它求三个数的最小值和最大值,每个只需要两次比较:#include <stdio.h> int main() { int a, b, c; scanf("%d%d%d", &a, &b, &c); int min = a < b ? a : b; /* a、b 中较小者 */ min = min < c ? min : c; /* 再与 c 比较,得到最小值 */ int max = a > b ? a : b; /* a、b 中较大者 */ max = max > c ? max : c; /* 再与 c 比较,得到最大值 */ printf("%d %d %d", min, a + b + c - min - max, max); return 0; }中间那个数有个巧妙的求法:三数之和减去最小值和最大值,剩下的自然就是中间值,省去一次判断。
两种写法对比:交换法排完序后 a、b、c 本身就有序,后续还要按顺序使用这三个数时更方便;三目法不动原始变量,一行求出一个最值,在"只需要最大值/最小值"的场合更简洁。按场景选用。
容易出错的细节
- 交换的三行必须写在大括号里:
if (a > b) { t = a; a = b; b = t; },漏了大括号,if 就只管第一句赋值,逻辑整个坏掉。 - 输出用空格分隔,三个数一行。
- 数据可能相等(如
2 2 2),交换逻辑对相等天然免疫,不需要特判。
复杂度
固定 3 次比较、最多 3 次交换,时间与空间复杂度均为 O(1)。推广到 n 个数就是 O(n²) 的冒泡排序。
三个数排序,三次比较保底——这个写法在下一章"三角形分类"里还会用到,先把交换练熟。
- 1
信息
- ID
- 517
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- (无)
- 递交数
- 19
- 已通过
- 3
- 上传者