top1编程
← 返回题目
题解

随机数排序

1 条题解

  • 0
    @ 2026-8-6 0:54:22

    P4656 随机数排序(入门)

    解题思路

    第一步,读懂题目。 小童生成了 n 个 1 到 100 之间的随机数,要按从大到小的顺序输出。注意重复的数字必须保留,不能去重,这和"去重排序"的题不一样。

    第二步,想到"桶排序"。 因为数字范围很小(只有 1 到 100),我们可以用"桶排序"(也叫计数排序),不需要把所有数先存下来再排序。开一个数组 numCnt,numCnt[v] 表示数字 v 出现了几次。

    第三步,读入时计数。 读入时,遇到数字 cur 就把 numCnt[cur] 加 1,这一步同时完成了"读入"和"统计"两件事。

    第四步,从大到小输出。 输出时,从 100 开始往下数到 1,如果 numCnt[v]=k,说明数字 v 出现了 k 次,就连续输出 k 个 v。因为我们是按 v=100、99、……、1 的顺序输出的,所以输出的顺序自然就是从大到小。

    第五步,用样例验证。 拿样例 1 4 2 3 1 1 来说:1 出现了 3 次,2、3、4 各出现 1 次。从大到小输出就是先输出 4,再输出 3,再输出 2,最后连着输出三个 1,得到 4 3 2 1 1 1。

    第六步,明白桶排序快的道理。 桶排序最大的好处是:n 再大也不用怕,因为只需要扫一遍输入,然后用 100 个桶记录每个数字出现的次数就够了,不需要把整个序列存下来。随机数的范围只有 1 到 100,如果用一般的比较排序,需要 O(n log n) 的时间;而桶排序只要扫一遍输入、再输出一遍,是 O(n) 的线性时间,快得多。如果题目要求从小到大输出,只需把循环改成从 1 到 100 正着输出即可,思路完全一样。排序算法不是越复杂越好,要根据数据的特点选择最合适的方法,这才是真正的高手思维。

    参考代码

    // P4656 随机数排序:数字范围只有 1~100,用桶(计数)排序从大到小输出
    #include <iostream>
    using namespace std;
    
    int numCnt[101];   // 桶:numCnt[v] 记录数字 v 出现的次数
    
    int main() {
        int n;
        cin >> n;                          // 读入随机数的个数
        for (int i = 0; i < n; i++) {      // 逐个读入每个随机数
            int cur;
            cin >> cur;
            numCnt[cur]++;                 // 数字 cur 的出现次数加一
        }
        bool firstOut = true;              // 标记是否已输出过数(用来控制空格)
        for (int v = 100; v >= 1; v--) {   // 从大到小检查每个数字
            for (int i = 0; i < numCnt[v]; i++) {   // 出现几次就输出几个
                if (!firstOut) cout << " ";         // 数之间用空格隔开
                cout << v;
                firstOut = false;
            }
        }
        cout << endl;
        return 0;
    }
    

    复杂度分析

    读入时遍历 n 个数,O(n);输出时每个数都被输出一次,也是 O(n)。再加上对 100 个桶的检查,总时间 O(n+100)。空间 O(100),是常数。这是所有排序算法里最快的一类,非常适合数字范围小的题目。

    • 1