1 条题解

  • 0
    @ 2026-10-8 21:09:25

    三位数排序

    一个自然的想法,和它的代价

    三个数从小到大输出。第一反应可能是枚举:三个数的大小关系一共 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 本身就有序,后续还要按顺序使用这三个数时更方便;三目法不动原始变量,一行求出一个最值,在"只需要最大值/最小值"的场合更简洁。按场景选用。

    容易出错的细节

    1. 交换的三行必须写在大括号里:if (a > b) { t = a; a = b; b = t; },漏了大括号,if 就只管第一句赋值,逻辑整个坏掉。
    2. 输出用空格分隔,三个数一行。
    3. 数据可能相等(如 2 2 2),交换逻辑对相等天然免疫,不需要特判。

    复杂度

    固定 3 次比较、最多 3 次交换,时间与空间复杂度均为 O(1)。推广到 n 个数就是 O(n²) 的冒泡排序。

    三个数排序,三次比较保底——这个写法在下一章"三角形分类"里还会用到,先把交换练熟。

    信息

    ID
    517
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    (无)
    递交数
    19
    已通过
    3
    上传者