集合的偽隨機遍歷

2021-07-16 23:58:25 字數 2000 閱讀 4889

有時候可能會遇到這樣的需求:

2.拼圖遊戲每次重新開始時需要隨機初始化碎片的位置,要求隨機出的位置不得重複

演算法:集合的偽隨機遍歷

語言:c++

輸入:源集合source

輸出:一連串不重複的隨機數,隨機數個數等於source集合元素的個數。

標頭檔案及全域性變數:

#include #include #include #include int gnum = 26;

char gsource[26] = ;

char gresult[26] = ;

std::unordered_setghashset;

方案一:第一次通過隨機數取得source集合中的元素後,存放到另乙個陣列(result陣列)當中;然後接下來每次取得source集合的元素後與result陣列內的元素比較,若有重複則重新取。

void test1()

} // 通過校驗

if (isdifferent)

gresult.push_back(gsource[temp]);

} for (const char& t : gresult)

}

方案二:將source集合中的元素隨機地插入到hashset中,直到hashsize長度等於集合長度。

void test2()

for (const char& t : ghashset)

}

這兩種方法得到資料都有點硬著頭皮上的感覺,其實隨機遍歷就像在跳著走一條直線,從某個元素開始前進x步或者後退y步,最終足跡踩遍整條直線。

void test3()

for (int i = 0; i < gnum; ++i)

while (nextmember <= 0 || nextmember > gnum);

gresult.push_back(gsource[nextmember-1]);

std::cout << nextmember-1<

} for (const char& t : gresult)

}

上述演算法要注意prime要大於gnum且是素數,如本例取prime為29(gnum=26),此時再由ra,rb,rc三個隨機取得的在1-29以內的數得到skip,要保證skip值可以被prime除盡。

額外輸出一下nextnumber-1,即隨機獲取的source集合索引數。比如,q對應26字母表中第17個字母,source[16].

可以觀察到,每個數字之間差值是有規律的(因為nextnumber每次+=skip值後%=prime):

-12,+17,-12,+5,-12,+17,-12,+17,-12,+17...

可以觀察到每次隨機取的索引數有一些規律:

1.當數字大於等於12時,每次後退12.

2.當數字小於等於8時,每次前進17.

3.當數字在大於8,小於12時,由於此時前進17會超過最大索引數25,所以前進5.

這樣一來,就偽隨機地遍歷了整個集合,同時其中的規律又可以由自己控制。

比如我們將prime換為31:

顯然,此時:後退15,前進16,超過索引時前進1.

那你有可能會覺得這樣一來隨機數似乎沒什麼神秘感了,容易被發現規律。

實際上我們可以寫乙個專門取素數的類primesearch,prime在每次「隨機」取完1-n個元素時,

prime = primesearch.getnextprime();,然後呢,primesearch內部如何取素數是我們可以提前定義的。

這樣一來,就可以定製出滿足需求的隨機遍歷了,較第

一、第二種方案更為高階。

的確是偽隨機

c語言的 裡 rand 函式可以產生 0 rand max 包括 之間的隨機數,通常是經過 srand 函式進行初始化後再使用。rand max 的值預設是 32767 即 2 15 1 在 裡的定義是 define rand max 0x7fff 所以如果需要求 a,b 顯然要有 b rand m...

偽隨機與實驗

眾所周知,計算機產生的是偽隨機數。所謂偽隨機,就是 當知道種子和隨機產生演算法之後,就可以完全確定出隨機數序列了。並且這個隨機數序列是迴圈重複的。不同的隨機產生演算法的迴圈週期不同 好的隨機產生演算法的迴圈週期會很長。有的文章提到,可以通過引入系統以外的變數來達到真隨機的目的,比如 unix 維護了...

偽隨機演算法同步

一般來說網遊要求邏輯在服務端計算,原因是一方面利於玩家之間邏輯同步的實現,另一方面伺服器做仲裁方,防止玩家作弊。但在有些情況下,由於一些邏輯要求的實時性很高,我們不得不把一些邏輯的判斷放在客戶端,以保證遊戲的流暢感。比如動作遊戲中,玩家受擊時的動作切換,如果需要根據屬性邏輯計算的結果切換到不同被動動...