logo

C语言实现生成不重复随机数及控制随机数范围方法详解

本站 745
在计算机编程中,尤其是在C语言这类底层、高效的语言环境下,生成一定范围内且无重复的随机数是一项常见的任务。本文将深入探讨如何利用C标准库函数以及算法设计来有效地实现在指定区间内产生一系列互斥(即不重复)的随机整数值。

首先,在C语言中我们通常使用stdlib.h头文件中的rand()函数作为基础进行随机数生成操作。然而原始的rand()产生的“随机”序列并非真正意义上的完全随机,并且其输出值在整个int类型可表示的范围内分布并不均匀,默认情况下每次程序运行会得到相同的伪随机数序列。为了解决这个问题并使得结果更具随机性,我们可以结合srandom(time(NULL))或 srand(seed)对随机种子初始化,其中seed是一个任意整数以确保不同次调用时能获得不同的序列表现。

c

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

// 初始化随机数发生器 seed 可以为当前时间或者其他变化的数据保证每次执行获取不一样的随机数流.
void init_randomizer(void){
srand((unsigned int) time(0));
}


接下来要解决的问题是如何限定这个随机数在一个特定的范围内。例如我们需要从1到50之间生成一个随机数,则可以采用取模和偏移的方式来调整:

c

int generate_unique_in_range(int lower_bound, int upper_bound){
// 确保upper_bound大于lower_bound
assert(lower_bound <= upper_bound);

return (rand() % (upper_bound - lower_bound + 1)) + lower_bound;
}


但是上述方法直接对 rand() 结果做%运算的话,当上界不是2^n-1这样的形式时会导致低区间的数字概率更大,因此对于大范围非连续或者需要绝对均衡的概率情况不太适用。

为了生成一段固定长度并且唯一(不存在重复项)的随机数列,一种常见策略是事先创建一个包含所有可能选项的大数组,然后对其进行原地打乱排序后取出前n个元素即可。这里可以借助Fisher-Yates shuffle算法(也称Knuth Shuffle),它可以在O(n)的时间复杂度下完成此目标:

c

#define MAX_RANGE 50

void FisherYatesShuffle(int arr[], size_t n) {
for(size_t i = n - 1; i > 0 ; --i)
{
unsigned char key = rand() % (i+1); // 随机索引避免了循环内的条件判断导致的偏差
swap(&arr[i], &arr[key]);
}
}

int unique_numbers[MAX_RANGE];
for(int i=0;i<MAX_RANGE;++i){unique_numbers[i]=i+1;}
FisherYatesShuffle(unique_numbers, MAX_RANGE);

// 此刻unique_numbers包含了[1, MAX_RANGE]的一个随机排列

如果内存资源有限不允许一次性存储全部候选集合的情况,另一种解决方案则是动态维护已使用的随机数记录,如通过哈希表等数据结构检查新抽取的随机数是否已经出现过。这种方法的空间效率更高但计算成本相应增加,尤其随着所需独特随机数数量的增长而更加明显。

总结来说,在C语言环境中实现生成给定范围内不重复随机数的方法取决于具体的应用场景与约束条件:简单的线性同余法配合适当变换能满足小规模需求;而对于大规模且要求严格的场合则需引入更复杂的统计学原理和技术手段,比如洗牌算法或是维持独立未选集等方式达成目的。同时应时刻注意保持良好的实践习惯,包括正确设置随机种子,处理边界问题以及优化空间/时间性能等因素。

标签: c语言不同随机数