【问题标题】:filling an array with random number用随机数填充数组
【发布时间】:2011-01-23 03:08:01
【问题描述】:

我正在尝试用 1-20 的数字以随机顺序填充 20 个整数的数组。 这是我的代码:

 int lookup[20]={0}; 
 int array[20]={0};
 srand(time(NULL));
 for(int i=0;i<20;++i){ 
    bool done=false;
    while(!done){
      int n=rand()%20;
      if(lookup[n]==0){
          array[i]=n;
          lookup[n]=1;
          done=true;
      }
    }
 }

我创建了一个查找数组来检查是否尚未选择随机数并将其存储在数组中。如您所见,我创建了 2 个循环,一个用于遍历数组,一个用于选择随机数。在每次 while 循环迭代中,数字可能会重新出现并导致另一个 while 循环。有更快的方法吗?

【问题讨论】:

标签: c++ c random


【解决方案1】:

您可以按顺序填充数组,然后随机播放。这样可以避免生成超过 20 个随机数。

Fisher-Yates shuffle: 可以在 O(n) 时间内完成。

来自维基百科:

如果实施得当,Fisher-Yates 洗牌是无偏的,因此每个排列的可能性都相同。该算法的现代版本也相当高效,只需要与被洗牌的项目数量成正比的时间,并且不需要额外的存储空间。

【讨论】:

  • 如果您专门使用 C++ 而不是 C,那么 graham.reeds 建议使用 std:random_shuffle 将带您到达您想去的地方,而不会在实施 shuffle 算法时出错。如果您使用的是 C,那么您可以在 Wikipedia 页面(也可能在网络上的其他地方)上有一个代码实现,您可以复制它。
  • 是的!我为此使用 C++。 std::random_shuffle 很好,但我想我会尝试实现 shuffle 算法。感谢您的回复。
  • 请记住,重新发明轮子也为重新发明各种明显和微妙的错误留下了空间。
【解决方案2】:

【讨论】:

  • 是的!使用标准算法; Fisher-Yates 很容易出错。
  • 我一直想知道为什么叫random_shuffle。有点暗示有一个nonrandom_shuffle
  • STL +1。数组也提供 RA 迭代器。不需要 std::vector。
  • 如果您打算使用 C++,那么您不妨充分利用 STL 所能提供的一切。
【解决方案3】:

您可以用 1 到 20 的数字填充数组并使用 std::random_shuffle

请注意,您不需要向量,只需简单的数组即可。
示例:

#include <iostream>
#include <algorithm>

using namespace std;

int main( void )
{
        int array[] = { 0, 1, 2, 3, 4 };

        srand( unsigned( time(NULL) ) );

        random_shuffle(array, array+5);

        for(int i=0; i<5; i++)
                cout << array[i] << endl;

        return 0;
}

【讨论】:

    【解决方案4】:

    您的代码中可能存在一个运行时间很长的循环。如果您在 while(!done) 循环中,则无法保证您会完成。显然,对于 20 个元素的数组,这在实践中不会成为问题,但如果将其扩展到数千个元素,则可能会导致问题。

    更可靠的解决方案是顺序填充数组,然后再随机播放。

    【讨论】:

    • “无法保证你会完成” - 如果随机数函数足够好,则循环以概率 1 终止,但你说得对,预期的运行时间很差。在数组长度大于 RAND_MAX 的情况下,您显然有问题,但这实际上与代码尝试从 0 .. N-1 均匀分布的随机数获取随机数的狡猾方式有关。执行rand()%N 的Fisher-Yates 对于大N 也很弱。
    • 你是对的,如果我扩大到 100 万个元素,它肯定会出现一些性能问题。
    【解决方案5】:

    我先把这20个随机数放到一个数组里,然后复制到另一个20个元素的数组中,对一个数组进行排序,对排序后的数组中的每个数,在未排序的数组中找到对应的数,并将索引放入那里的那种。

    【讨论】:

      【解决方案6】:

      如果你可以使用容器,我只需用 1 到 20 的数字填充 std::set。

      然后你可以从你的集合中提取一个随机数并将其插入到数组中。

      【讨论】:

        【解决方案7】:

        其他可能的方式

        int array[20]={0};
        int values[20];
        for(int i = 0; i < 20; i++)
            values[i] = i;
        int left = 20;
        for(int i = 0; i < 20; i++)
        {
            int n = rand() % left;
            array[i] = values[n];
            left--;
            values[n] = values[left];
        }
        

        PS 填充的数字是从 0 到 19,而不是从 1 到 20。与原始编号相同

        【讨论】:

        【解决方案8】:

        Fisher-Yates 的代码示例:

        #include <stdio.h>
        #include <stdlib.h>
        #include <time.h>
        
        void shuffle(int array[], size_t size)
        {
            if(size) while(--size)
            {
                size_t current = (size_t)(rand() / (1.0 + RAND_MAX) * (size + 1));
                int tmp = array[current];
                array[current] = array[size];
                array[size] = tmp;
            }
        }
        
        int main(void)
        {
            srand((int)time(NULL));
            rand(); // throw away first value: necessary for some implementations
        
            int array[] = { 1, 2, 3, 4, 5 };
            shuffle(array, sizeof array / sizeof *array);
        
            size_t i = 0;
            for(; i < sizeof array / sizeof *array; ++i)
                printf("%i\n", array[i]);
        
            return 0;
        }
        

        【讨论】:

          【解决方案9】:

          希望对你有帮助:

          std::generate(array, array + sizeof(array)/sizeof(int), ::rand);
          

          下面是完整的代码:

          #include<algorithm>
          #include<cstdlib>
          #include<iostream>
          #include<iterator>
          
          int main()
          {
              int array[] = {1, 2, 3, 4};
              const unsigned SIZE = sizeof(array)/sizeof(int);
          
              cout << "Array before: ";
              std::copy(array, array+SIZE, std::ostream_iterator<int>(cout, ", "));
          
              std::generate(array, array+SIZE, ::rand); // answer for your question
          
              cout << "\nArray arter:  ";
              std::copy(array, array+SIZE, std::ostream_iterator<int>(cout, ", "));
          }
          

          如果你想得到比这个更小的数字,你可以在生成后这样做:

          std::transform(array, array+SIZE, array, std::bind2nd(std::modulus<int>(), 255));
          

          【讨论】:

            【解决方案10】:

            这样的?

            int n = 20; //total element of array
            int random = 0, temp=0, start=1;
            
            for(int i=0; i < n; ++i,++start)
            {
                array[i] = start;
            }
            
            for(int i=0; i<n ; ++i) 
            {
                random=rand()%(n-i)+i;
                //swapping, you can make it as a function
                temp = array[i];
                array[i] = array [random];
                array[random] = temp; 
            
            }
            

            【讨论】:

              猜你喜欢
              • 2017-06-04
              • 2013-09-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-04-18
              • 2011-11-29
              相关资源
              最近更新 更多