亂序算法及C++函數

我們經常看到排序的算法,但有的時候,也需要將某個有序的序列打亂順序,就叫“亂序”吧。
按排序的定義,“亂序”應該是這樣的:將一組記錄(或者元素,本身可以是有序或者無序的)按照某
個域的值(稱之爲“排序碼”)的隨機次序重新排列的過程。
這裏我們注意到無論是排序還是亂序,都是按某個域的值進行的。比如我們將一組數據存放在
某個數組中,需要進行亂序,則只需要將數據下標(1-N)進行亂序後,再依次輸出數組的內容,就可以
達到亂序的目的了。
一提到隨機,當然免不了需要用到隨機函數,這裏並不打算討論隨機的深入算法,只說明隨機
函數在亂序算法中的使用。隨機函數一般都不是真正的隨機,而是通過算法在某個範圍內按某個分佈函
數生成的隨機數。在VB中,Rnd()函數可以生成0-1之間的隨機小數,然後再通過運算得到想要的分佈範
圍;在C++中,使用rand()函數可以生成0-RAND_MAX(0x7ffff)之間的整數,也同樣需要經過運算。當然
爲了每次生成的隨機數不同,在VB中使用Rnd()函數之前,要先用Randonize time 語句,使用當前時間作
隨機種子;而在C++中,則可以用 srand((unsigned)time(NULL)); 來設置隨機種子。要說明的是,隨機種
子語句一般只用一次,多次使用反而會使隨機函數"不隨機"了。這裏僅以C++爲例,來寫一個自定義的函數,
這個函數的作用是,輸入整數a和b,隨機生成[a,b]之間的整數(Echo注:這個[a,b]是指區間,即生成的數
是包含a和b的)。

//生成a,b 之間的隨機整數
int Random (int a, int b)
{
int area=0;
int ret=0;
//生成區間
area=b-a+1;
ret=(int)(rand()*area/(1.0 * RAND_MAX)+a);
return ret;
}

說完了隨機函數,我們再來看看如何亂序。假設我們先把需要亂序的數保存在一個數組A中,另外
建一個與A數組一樣大小的數組B,來存放亂序後的結果。
算法一:這是經常看到的算法
(1)從A中隨機抽取一個數;
(2)查一下B中是否已經有這個數
(3)如果B中沒有,則把這個數放到B中;如果有表示重複了,再回到(2)
(4)直到B中的數組滿了,結束;

這裏存在兩個問題:
1、在步驟(2)中去檢查已經隨機抽出來的數是不是有被抽過,這本身就存在問題,因爲有可能在A中某個數
本身就是出現多次,比如這樣一個序列:"1,2,4,5,2,3,4,7,22" 數字2和4都出現的2次。所以這種判斷方式只能
用於不出現重複的情況;
2、設想一下隨機抽取最後一個數的情況,假設一個序列“1,2,3,4,5,6,7" 隨機抽取6次後得到"5,3,1,2,4,7"
就剩下最後一個數字6了,但是這時在第(1)步中是隨機抽取一個數,程序會在1-7中隨機選擇一個數,有可能
重複了很多次後仍沒有選出6這個數,但實際上,這時已經不需要再隨機了,只有6纔可以被抽取。
通過算法一我們可以看出亂序不能以抽取的數據內容作爲標準,而應該是這樣一種方式:先將需要亂序
的數放到臨時數組A中,然後:
算法二: 
(1)從A中隨機抽取一個數K,並放入B中;
(2)從A中把K刪除;
(3)回到第(1)步,直到A中爲空
使用這種方式,可以不需要理會A中數據是否重複,同時,每次到步驟(2)後,A中的數據個數就少1,也不需要
進行判斷。這其實也符合實際生活中我們打亂順序的過程:隨機抽一張牌,放到外面;再隨機抽一張牌,放到原
剛纔那張的上面,直到結束。
讓我們看看C++的程序,下面的程序是給直接在數組中進行亂序,每次隨機選擇一個位置,把它與最後一
個位置的數據對換,直到結束。

//生成0-n不重複的隨機數字
void GetRand(int n,int arr[])
{
int i;
int p;
int tmp;
for (i=0;i<=n;i++)
{
   arr[i]=i;
}

for (i=n;i>0;i--)
{
   p=Random(0,i);
   tmp=arr[p];
   arr[p]=arr[i];
   arr[i]=tmp;
}
}

在主程式調用上面函數時,需要先用 srand((unsigned)time(NULL));語句來設置隨機種子。生成隨機數組後,
即可使用下標的方式引用數據了。測試的主程式沒有寫,有興趣的朋友可以自己完成,其實只要輸出arr[]的值
就看以看到亂序後的結果了。

Echo備註:GetRand函數裏沒有檢查arr[]的大小,有可能會出現錯誤,請保證arr下標爲0-n,即大小爲n+1。


http://blog.chinaunix.net/uid-20520151-id-3069077.html

發佈了55 篇原創文章 · 獲贊 5 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章