洗牌数组

Shuffling an array

这段代码应该做的是打乱一个数组,然而每次我 运行 它在一个我得到相同的 "shuffled" 数组(当然通过输入相同的未打乱的数组) 我认为 srand(time(NULL)); 部分将确保这一点。如果不是这样,我不知道如何让它真正随机播放。

总而言之,我需要知道为什么我的代码每次都以相同的方式洗牌。

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


int main(){

    int n;
    int m;
    int tmp;
    int i;

    printf("Please input the number of elements in your array:\n"); 
    scanf("%d", &n);

    int baraja[n];
    int tempbaraja[n];
    for (int i = 0; i < (sizeof(baraja)/sizeof(baraja[0])); i ++){
        printf("Please input the %d element of your array:\n",i);
        scanf("%d",&baraja[i]);
    }
    printf("Unshuffled array:\n");
    for (i=0;i < n;i++) {
        printf(" %d \n",baraja[i]);
    }
    for (int i = 0; i < n; i ++){ 
        tempbaraja[i] = baraja[i];
    }
    for (int i = 0; i < n; i ++){ 
        srand(time(NULL));
        m = rand() % n; 
        if (tempbaraja[m] == baraja[m]){ 
            tmp = baraja[m];
            baraja[m] = baraja[i];
            baraja[i] = tmp;
        }else{
        }
    } 
    printf("Shuffled array:\n");
    for (i=0;i < n;i++) {
        printf(" %d \n",baraja[i]);
    }   
}

您需要将 srand(time(NULL)); 移到 for 循环之外。

如您所见,rand() 是一个 伪随机数 数字生成器。 srand()用于提供种子rand()将根据该种子生成随机数。

如果每次在调用 rand() 之前用相同的 time(NULL) 播种 rand() 的每个结果都将是一样。

为了达到预期的结果,您只需要使用 srand() 为随机数生成器 播种一次 ,然后在每次调用 rand() 时,它会给你随机数。

注意:虽然这不是强制性的,但在 main() 的末尾有一个明确的 return 0 是一个很好的做法。

让 srand(time(NULL)) 脱离循环。

来自srand reference

Two different initializations with the same seed will generate the same succession of results in subsequent calls to rand.

因此,对于每次迭代,您都在初始化随机数生成器并获取第一项,这始终是相同的。

您误用了 srand,它只应在循环外调用一次。这也是 srandrand 实现在您 运行 所在的平台上可能特别糟糕的机会,如果程序快速重新执行会导致性能不佳。

glibc srand() 手册页,其中指出:"The srand() function sets its argument as the seed for a new sequence of pseudo-random integers to be returned by rand(). These sequences are repeatable by calling srand() with the same seed value." 具体来说,您的程序可能违反了以下条款:“..序列可以通过使用相同的种子值调用 srand() 来重复。”因为它可以随时间每秒多次播种 rand() - 导致相同的伪随机数序列。

好的,我会回答后续问题。为什么 srand() 循环不好?

rand() 函数生成一系列可接受的随机数,根本不需要 srand()。问题是它是一个固定的序列,所以每次你 运行 这个程序,你都会得到相同的一组 "random" 个数字。

srand(time(NULL)) 的目标是选择一个不同于任何先前起始值的起始值。 time() 函数调用仅用于选择不同的起点,缺点是结果每秒仅更改一次。 运行 程序在同一秒内运行两次可能是从脚本文件或批处理作业启动的程序的问题,但通常不是从键盘或鼠标事件启动的程序。

所以,在循环中使用 srand(time(NULL)) 有一个主要的恶果。每一挂钟秒你只能得到一个新的随机数。

即使你有一个高精度定时器来采样,或者使用:

    unsigned counter = time(NULL);
    srand(counter++);

..选择不同的起始值,还是有问题。从顺序起点选择的随机数的分布不像整个序列那样"random",并且对于某些生成器来说可能非常糟糕。如果您的起始点来源足够随机,可以从 srand();rand(); 得到好的结果,那么您可能根本不需要 rand()。您可以直接使用这些起始值!

最后,srand() 会减慢您的程序。特别是 Visual C++ 的 rand()srand() 是出了名的慢,而 MinGW 也使用该库。 (技术问题是由于将种子值存储在线程本地存储中,每次调用需要 100 多条指令才能找到。)但是,即使是静态链接的非线程安全版本也涉及额外的调用和 return你不需要。

这些是我所知道的不在循环中使用 srand() 的主要原因。大多数开发人员会对 "it's not necessary".

感到满意