【问题标题】:Shuffling an array洗牌数组
【发布时间】:2015-04-15 13:46:31
【问题描述】:

这段代码应该做的是洗牌一个数组,但每次我在 a 上运行它时,我都会得到相同的“洗牌”数组(当然通过输入相同的未洗牌数组)我认为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)) 应该只被调用一次,最好在程序开始时调用。
  • @remyabel 能否请您具体扩展您的答案,为什么如果我迭代每次迭代时种子都会改变,为什么只调用一次?
  • 因为srand()rand() 序列重置为已知的可重复点。所以rand() 总是返回相同的“随机”(不是!)数字。通过在程序开始时调用srand(time(NULL)),每次运行都会得到不同的序列。

标签: c arrays random shuffle


【解决方案1】:

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

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

如果在每次调用rand() 之前,您每次种子使用相同的time(NULL),那么rand() 的每个结果都将是相同的。

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

注意:虽然这不是强制性的,但最好在 main() 的末尾加上明确的 return 0

【讨论】:

  • @CarlosSanchez 正在更新我的答案以解决您的问题。现在有用吗?
【解决方案2】:

让 srand(time(NULL)) 退出循环。

来自srand reference

使用相同种子的两个不同初始化将生成 在后续调用 rand 时会产生相同的连续结果。

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

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

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

      即使您有一个高精度计时器可供采样或使用:

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

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

      最后,srand() 会减慢您的程序。众所周知,Visual C++ 的速度很慢 rand()srand(),MinGW 也使用该库。 (技术问题是由于将种子值存储在线程本地存储中,每次调用需要超过 100 条指令才能找到。)但是,即使是静态链接的非线程安全版本也需要额外的调用和返回,而你不需要'不需要。

      这些是我所知道的不在循环中使用srand() 的主要原因。大多数开发人员都会对“没有必要”感到满意。

      【讨论】:

        【解决方案5】:

        glibc srand() 手册页,其中指出:“srand() 函数将其参数设置为由 rand() 返回的新伪随机整数序列的种子。这些序列可通过调用 srand 来重复() 具有相同的种子值。”具体来说,您的程序可能违反了以下条款:“通过调用具有相同种子值的 srand() 可以重复序列。”因为它可以每秒播种 rand() 多次,从而产生相同的伪随机数序列。

        【讨论】:

        • 您好,欢迎来到stackoverflow!感谢您抽出时间帮助解决问题。但是,如果您在解决问题的方法中添加一些描述,那将很有帮助。另外,请尽量不要发布只有一行(或两行)更改的整个代码。恕我直言,对问题的说明和准确的说明会更好。 :-)
        猜你喜欢
        • 2013-06-28
        • 1970-01-01
        • 1970-01-01
        • 2019-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        相关资源
        最近更新 更多