如何避免rand()生成重复随机数?if else结构是否可行?
无重复随机数的实现方案
仅用if else确实能实现不重复的随机数生成,但效率不算高,更推荐用洗牌算法来处理,下面具体说明两种方式:
一、用if else+重试的方式实现
思路是:每次生成随机数后,遍历已经存入数组的元素,检查是否重复。如果重复,就重新生成随机数,直到拿到不重复的值。
需要注意的是,你的原代码里用了time(NULL)但没包含<time.h>,编译时会有警告,记得补上。修改后的代码如下:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(int argc, char *argv[]) { srand(time(NULL)); int i, j; int dizi[20]; for (i = 0; i < 20; i++) { int num; int is_duplicate; do { num = rand() % 20; is_duplicate = 0; // 检查当前数是否和之前的重复 for (j = 0; j < i; j++) { if (dizi[j] == num) { is_duplicate = 1; break; } } } while (is_duplicate); // 重复就重试 dizi[i] = num; } for (i = 0; i < 20; i++) { printf("%d\n", dizi[i]); } return 0; }
这种方法的问题在于:当数组快填满时(比如生成第19、20个数时),重复的概率会非常高,可能需要多次调用rand()才能拿到未出现过的数,效率较低。
二、更高效的洗牌算法(Fisher-Yates)
思路是:先初始化一个包含0到19的有序数组,然后通过随机交换数组元素的位置,得到一个无重复的随机序列。这种方法的时间复杂度是O(n),效率远高于重试法。
代码示例:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(int argc, char *argv[]) { srand(time(NULL)); int i; int dizi[20]; // 先初始化数组为0到19的有序序列 for (i = 0; i < 20; i++) { dizi[i] = i; } // Fisher-Yates洗牌:从后往前交换 for (i = 19; i > 0; i--) { // 生成0到i的随机索引 int rand_idx = rand() % (i + 1); // 交换当前元素和随机索引的元素 int temp = dizi[i]; dizi[i] = dizi[rand_idx]; dizi[rand_idx] = temp; } // 输出结果 for (i = 0; i < 20; i++) { printf("%d\n", dizi[i]); } return 0; }
这种方法能保证每个数只出现一次,且随机分布均匀,没有重试的开销,是生成无重复随机序列的最优方案。
内容的提问来源于stack exchange,提问作者0CalamityKing0
相关产品推荐
相关产品推荐

