1、問題描述
給定一個正整數n,需要輸出一個長度為n的數組,數組元素是隨機數,範圍為0 – n-1,且元素不能重複。比如 n = 3 時,需要擷取一個長度為3的數組,元素範圍為0-2。
2、準備
首先,讓我們先構造如下函數:
//隨機數產生函數,產生[a,b]之間的一個隨機數字//其中0<=a<b<=RAND_MAX(即2^15-1=32767)int random(int a,int b){return a+rand()%(b-a+1);}
3、解法一
先給序列A[0...n-1]賦值,A[i]=i;(0=<i<n)。然後為每個元素A[i]賦一個優先順序P[i],然後依據優先順序對序列A進行排序。這裡要保證序列P中沒有相同的元素,所以P[i]的取值範圍可以選[0,(n-1)^3]。這樣就儘可能保證P中元素無重複。虛擬碼如下:
n=length[A]for(i=0;i<n;i++) P[i]=random(0,n^3);sort A,using p as sort keys
分析:顯然解法一無法準確的確保P中元素無重複,且當n較大時,n的三次方會很大,如當n=10000時,n的三次方已經超出了無符號長整形的表示範圍。該演算法時間複雜度依賴排序時間,且這個排序不好實現。總之,這不是一個很好的隨機序列產生演算法。
4、解法二
先給序列A[0...n-1]賦值,A[i]=i;(0=<i<n)。然後原地排列給定序列。代碼如下:
//產生隨機序列void randomSequence1(int *a,int n){int i,r,temp;for(i=0;i<n;i++)a[i]=i;srand(time(NULL));for(i=0;i<n;i++){r=random(i,n-1);//交換temp=a[i];a[i]=a[r];a[r]=temp;} }
分析:這個演算法的時間複雜度為o(n)。
5、解法三
這是在網上看的一種高效隨機產生序列演算法,詳細請看原文:http://www.cnblogs.com/eaglet/archive/2011/01/17/1937083.html
這裡給出自己寫的代碼:
//產生隨機序列void randomSequence2(int *a,int n){int i,end,r;int *q=(int *)malloc(sizeof(int)*n);for(i=0;i<n;i++)q[i]=i;srand(time(NULL));end=n-1;for(i=0;i<n;i++){r=random(0,end); a[i]=r;q[r]=q[end];end--;} }
6、附錄
參考書籍:《演算法導論》 解法三原文:http://www.cnblogs.com/eaglet/archive/2011/01/17/1937083.html