2010-03-03 193 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));