C++中的随机数看这里应该够用

首先需要说明,C标准库可以在C++中使用。srand()和rand()均来源于<cstdlib>中。因为这两个函数只能生成相对随机的伪随机数(有规律的随机数),这种不能直接实现“绝对随机”的函数一开始会给大家带来一些疑惑。下面记录了一些关于srand()和rand()的使用方法,以及如何实现伪随机数的“绝对随机”。

一、srand()和rand()函数

1、srand()

void srand(unsigned seed);

srand(seed)函数是rand()函数的种子,用于初始化rand()函数的初始值。

2、rand()

int rand(void); // 指定从seed开始,返回一个[seed, RAND_MAX(0x7fff)]的随机整数

情况1

调用rand()函数时,若没有在之前调用srand(seed)函数,系统会自动将seed默认为1,执行srand(1)函数,从而返回一个[1, RAND_MAX(0x7fff)]的随机整数。

情况2

调用rand()函数时,若在之前调用了srand(seed)函数,则会返回一个[seed, RAND_MAX(0x7fff)]的随机整数。

二、经典案例

在[0, 6)区间随机取得一个整数

1、未使用srand(unsigned seed)函数指定seed值

const int cnt = 6;
for(int i=0; i<10; i++)
{
	cout << "TRY_" << i+1 << ": " << rand() % cnt << endl;
}
TRY_1: 1
TRY_2: 1
TRY_3: 5
TRY_4: 2
TRY_5: 4
TRY_6: 2
TRY_7: 0
TRY_8: 2
TRY_9: 5
TRY_10: 1

默认seed=1,每次执行都输出同样的结果。

2、使用了srand(unsigned seed)函数指定seed=1

const int cnt = 6;
srand(1); // 这里添加了seed=1
for(int i=0; i<10; i++)
{
	cout << "TRY_" << i+1 << ": " << rand() % cnt << endl;
}
TRY_1: 1
TRY_2: 1
TRY_3: 5
TRY_4: 2
TRY_5: 4
TRY_6: 2
TRY_7: 0
TRY_8: 2
TRY_9: 5
TRY_10: 1

通过srand(1)设定seed的初始值为1,每次执行都输出同样的结果,且与案例1结果相同。
这里也从侧面验证了案例一中,若不调用srand(unsigned seed),系统就会调用srand(1)函数的事实。

3、使用了srand(unsigned seed)函数指定seed为3

const int cnt = 6;
srand(3); // 这里添加了seed=3
for(int i=0; i<10; i++)
{
	cout << "TRY_" << i+1 << ": " << rand() % cnt << endl;
}
TRY_1: 3
TRY_2: 3
TRY_3: 1
TRY_4: 5
TRY_5: 5
TRY_6: 0
TRY_7: 0
TRY_8: 4
TRY_9: 1
TRY_10: 1

虽然和前两个案例结果不同,但每次运行结果相同。

4、实现“完全随机”案例

#include <ctime>
const int cnt = 6;
srand((unsigned)time(0));
for(int i=0; i<10; i++){
	cout << "TRY_" << i+1 << ": " << rand() % cnt << endl;
}

这里引入了<ctime>,将seed值指定为当前流逝的时间。因为时间是不停变化的,所以每次运行时,我们所得到的seed值都在改变,从而导致每次获取的结果均不相同。

第一次运行

TRY_1: 4
TRY_2: 4
TRY_3: 4
TRY_4: 0
TRY_5: 5
TRY_6: 4
TRY_7: 0
TRY_8: 1
TRY_9: 1
TRY_10: 4

第二次运行

TRY_1: 4
TRY_2: 5
TRY_3: 1
TRY_4: 5
TRY_5: 2
TRY_6: 4
TRY_7: 1
TRY_8: 1
TRY_9: 1
TRY_10: 3

第三次运行

TRY_1: 4
TRY_2: 0
TRY_3: 3
TRY_4: 3
TRY_5: 5
TRY_6: 4
TRY_7: 3
TRY_8: 4
TRY_9: 4
TRY_10: 2

第n次运行...

TRY_1: 0
TRY_2: 4
TRY_3: 1
TRY_4: 4
TRY_5: 2
TRY_6: 1
TRY_7: 2
TRY_8: 4
TRY_9: 4
TRY_10: 5

5、关于取随机数这件事

[a,b)区间中随机取得一个整数,公式为:

(rand() % (b-a)) + a; // 左闭右开

三、产生不重复的随机数

通过细心观察可以发现:在上述案例中,[a, b)这个范围内虽然可以保证随机结果不同(非伪随机),但每次随机的元素难免会出现重复。若a与b的区间足够大,那么出现元素随机重复的概率就会很小;相对地,区间小的时候,出现重复随机数的概率就会变大。

那么,有没有一种写法可以产生完全随机且不重复的随机数呢?参考如下代码。

vector<int> rand_no_duplicated(int begin, int end, bool prt_out) {
    int i;
    int arr_len;
    vector<int> vec_arr;
    if (begin >= end) {
        cout << "======rand_no_duplicated()======" << endl;
        cout << "Illegal parameter: begin >= end" << endl;
        return vector<int>{0};
    }
    if (begin == 0) {
        arr_len = end + 1;
    }
    if (end == 0) {
        arr_len = abs(begin) + 1;
    }
    if (begin < 0 && end < 0) {
        arr_len = abs(begin) - abs(end) + 1;
    }
    if (begin > 0 && end > 0) {
        arr_len = end - begin + 1;
    }
    if (begin < 0 && end > 0) {
        arr_len = abs(begin) + end + 1;
    }
    for (i = 0; i <= arr_len - 1; ++i) {
        vec_arr.push_back(begin++);
    }
    cout << endl;
    // 随机产生从0到m-2个数组下标,把这个下标的元素值跟m-1下标的元素值交换,一直进行到下标为1的元素。
    srand((unsigned) time(0));
    for (i = arr_len - 1; i >= 1; --i) {
        swap(vec_arr[i], vec_arr[rand() % i]);
    }
    // 是否打印
    if (prt_out == true) {
        cout << "======rand_no_duplicated()======" << endl;
        cout << "arr_len: " << arr_len << endl;
        cout << "arr: " << "";
        for (i = 0; i < arr_len; i++) {
            cout << vec_arr[i] << " ";
        }
        cout << endl;
    }
    return vec_arr;
}
// 测试1
rand_no_duplicated(-3, 2, true); // 左闭右闭
======rand_no_duplicated()======
arr_len: 6
arr: 1 -3 -2 2 0 -1 
======rand_no_duplicated()======
arr_len: 6
arr: -1 -3 1 2 0 -2 
======rand_no_duplicated()======
arr_len: 6
arr: 0 -1 1 -2 2 -3 
// 测试2
rand_no_duplicated(0, 2, true); // 左闭右闭
======rand_no_duplicated()======
arr_len: 3
arr: 2 0 1 
======rand_no_duplicated()======
arr_len: 3
arr: 1 2 0 
// 测试3
rand_no_duplicated(-6, -1, true); // 左闭右闭
======rand_no_duplicated()======
arr_len: 6
arr: -4 -1 -5 -6 -3 -2 
======rand_no_duplicated()======
arr_len: 6
arr: -1 -4 -2 -5 -6 -3 
======rand_no_duplicated()======
arr_len: 6
arr: -5 -3 -2 -1 -6 -4 
// 测试4
rand_no_duplicated(3, 10, true); // 左闭右闭
======rand_no_duplicated()======
arr_len: 8
arr: 10 7 3 8 5 9 4 6 
======rand_no_duplicated()======
arr_len: 8
arr: 7 8 6 3 10 9 5 4 
// 测试5
rand_no_duplicated(-5, 0, true); // 左闭右闭
======rand_no_duplicated()======
arr_len: 6
arr: 0 -1 -5 -4 -3 -2 
======rand_no_duplicated()======
arr_len: 6
arr: -4 -1 -2 0 -3 -5 
//测试6
rand_no_duplicated(-5, -12, true); // 左闭右闭
======rand_no_duplicated()======
Illegal parameter: begin >= end
posted @ 2023-06-02 22:40  顺心无忧  阅读(118)  评论(0编辑  收藏  举报