生成1到20之间5个不重复整数的更优算法求解
原有代码的问题
- 不要把
srand((unsigned)time(NULL))放在函数内部:time函数返回的时间戳精度是秒,如果你1秒内多次调用getRandom,会得到完全一样的随机序列,建议把srand放到程序启动的入口处只执行一次。 - 去重逻辑有隐患:如果生成了重复值,你直接对
i--,但内层循环是遍历整个已生成的数组,一旦出现重复会多次触发i--,可能导致索引异常;另外极端情况如果持续生成重复值,实际循环次数会远超预期,并不是稳定的常数时间执行。 - 返回静态数组的设计有风险:静态数组的内存是全局共享的,多次调用函数会覆盖上一次的结果,如果你需要保存多组结果很容易出问题。
更优的实现方案
你要生成的是1-20范围内5个不重复的数,范围非常小,用Fisher-Yates洗牌算法是最稳妥的,完全不会有重复问题,逻辑也更简洁:
#include <stdlib.h> #include <time.h> #include <stdio.h> // 调用前确保已经在主函数执行过一次srand((unsigned)time(NULL)) int* getRandom() { static int res[5]; int nums[20]; // 先生成1-20的有序数组 for (int i = 0; i < 20; i++) { nums[i] = i + 1; } // 洗牌:只需要洗前5次就能拿到结果 for (int i = 0; i < 5; i++) { // 从[i,19]范围内随机取一个下标 int r = i + rand() % (20 - i); // 交换元素 int temp = nums[i]; nums[i] = nums[r]; nums[r] = temp; // 直接取当前位置的元素作为结果 res[i] = nums[i]; printf("%d\n", res[i]); } return res; }
这个方案的优势
- 完全没有重复的可能,不需要额外做去重判断,执行次数是固定的25次,比原有实现的最坏情况要稳定很多。
- 逻辑简洁,不容易出边界错误。
如果你后续需要处理的范围很大(比如要从10000个数里取10个不重复的),那用哈希集合存已经生成的数,判断重复的效率会更高,你当前的场景用洗牌算法就足够了。
内容的提问来源于stack exchange,提问作者Rectanguloid
相关产品推荐
相关产品推荐

