2010-03-03 161 views
10

我试图用随机序列填充数字从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循环。有没有更快的方法来做到这一点?

+0

apply random-number-generator tag – 2010-03-03 10:02:49

+0

另见:http://stackoverflow.com/questions/1218155/random-number-but-dont-repeat,http://stackoverflow.com/questions/1816534/random -playlist-algorithm,http://stackoverflow.com/questions/417831/what-is-the-best-way-of-randomly-re-arranging-a-list-of-items-in-c,http:/ /stackoverflow.com/questions/813935/randomizing-elements-in-an-array – outis 2010-03-03 14:07:16

回答

19

你可以按顺序填充数组,然后洗牌。这将阻止必须经历超过20次随机数生成。

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

维基百科:

执行得当,费雪耶茨洗牌是公正的,让每一个排列是同等可能。该算法的现代版本也相当高效,只需要与被混洗的物品数量成正比的时间,并且不需要额外的存储空间。

+1

确实! Knuth Shuffle。 – 2010-03-03 09:59:15

+0

如果你专门使用C++而不是C,那么graham.reeds使用std:random_shuffle的建议将使你在没有执行shuffle算法的错误的危险的情况下到达你想要去的地方。如果您使用的是C,那么在维基百科页面(可能在网络上的其他地方)有一个可以复制的代码实现。 – sfg 2010-03-03 11:16:00

+0

是的!我为此使用C++。 std :: random_shuffle是很好的去,但我想我会尝试实施shuffle算法。谢谢回复。 – James 2010-03-03 12:57:04

0

我把20张随机数的数组,然后复制到其他20个元素的数组,排序一个数组,并为有序阵列中的每个数字,发现排序的数组中相应的数字,并把那里的排序索引。

+0

其O(n * n)对不对? – 2010-03-03 10:01:16

9

你可以从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; 
} 
1

有你一个很长的运行循环的代码的可能性。如果你在while(!done)循环中,那么你不能保证完成。显然,对于20个元素的数组,这实际上不会成为问题,但如果将这个数量扩展到数千个元素,则可能会导致问题。

更可靠的解决方案是按顺序填充阵列,然后再洗牌。

+0

“不能保证你永远不会完成” - 如果随机数函数足够好,循环以概率1终止,但是你说得很对,因为预期的运行时间很差。在数组的长度大于RAND_MAX的情况下,你显然有问题,但实际上这与代码试图从0 .. N-1得到一个均匀分布的随机数的方式有关。对于大N来说,'rand()%N'的Fisher-Yates也是弱的。 – 2010-03-03 11:38:19

+0

你是对的,如果我扩展到100万个元素,它肯定会遇到一些性能问题。 – James 2010-03-03 13:03:21

15
+0

是的!使用标准算法;费希尔 - 耶茨很容易犯错。 – 2010-03-03 10:04:49

+3

我一直在想,为什么它被称为'random_shuffle'。这意味着有一个'nonrandom_shuffle'。 – 2010-03-03 10:08:45

+0

STL +1。数组也提供RA迭代器。不需要std :: vector。 – pmr 2010-03-03 10:56:11

0

如果你可以使用的容器,我只需填写一个std ::与数字设置为从1到20

然后你就可以从您所设定的拉一个随机数,然后将其插入阵列。

0

这样的事情?

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; 

} 
0

其它可能的方式

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填充nombers从0到19不从1至20。费舍尔 - 耶茨保持原来的

+0

不要使用'rand()%left' - 参见例如http://members.cox.net/srice1/random/crandom.html – Christoph 2010-03-03 10:46:56

0

代码示例:

#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; 
} 
0

我希望这将有助于:

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));