洗牌复原次数c语言公式,洗牌算法Fisher-Yates以及C语言随机数的产生
前些天在蘑菇街的面試中碰到一道洗牌的算法題,拿出來和大家分享一下!
原題是:54張有序的牌,如何無序的發給3個人?
這個題是運用經典的洗牌算法完成。首先介紹一種經典的洗牌算法--Fisher-Yates.現在大家在網上看到,大多是Fisher-Yates算法的變形。將本來O(n2),簡化到了O(n).代碼如下:
#include
#include
void func(char *, int);
void main()
{
char a[7] = {'a','b','c','d','e','f'};
func(a,6);
//a[7] = '\0';
puts(a);
}
void
func(char *date, int length){
char t; //t為交換字符空間
int i, j;
while(--length){
srand(time(0));
i = rand()%(length+1);
t = date[i];
date[i] = date[length];
date[length] = t;
}
}
算法的思路就是:
a,選中未操作的最后1個位置,在1至該位置之間產生一個隨機數(包含這兩個值),
b,然后交換這兩個值,造成的結果就是在未操作的所有牌中隨機的取一張放到未操作的牌底(數組尾),然后length-1使未操作的范圍減一,
c,重復上面步驟,直到未操作的值為1停止
代碼寫的很清晰,也很簡單。網上還有很多種方法。但通過大量的測試,可以給出肯定,改進后的Fisher-Yates算法,即上述代碼,已經是洗牌算法中很好的一個了。即簡單,隨機性又好。所以如果在面試中給出上述答案,就基本可以進行下一個問題了。如果面試官還覺得不夠。可以從代碼的完整性和魯棒性(劍指offer中有提到具體做法),如參數正確性,遇到無效輸入等方面改進?;蛘邇灮S機值。
關于優化隨機值,這里我們還可以再提一點。
首先必須肯定的一點是:計算機中的隨機數并不是真正的隨機數,它是一種偽隨機數,是通過某些公式計算出來的隨機數,通過改變式子中參數的值從而達到隨機的效果。雖然是偽隨機數,但其實已經可以達到我們編程中的要求了。
C語言中生成隨機數的函數有4個,兩兩搭配使用:
int rand(void); ? ? ? ? ? ? ? ? ?返回 0 ------- RAND_MAX 之間的一個 int 類型整數,該函數為非線程安全函數。并且生成隨機數的性能不是很好,已經不推薦使用。
void srand(unsigned int seed);????????? 設置種子值,一般與“當前時間 + 進程ID”作為種子,如果沒用調用該函數,則通過rand返回的默認種子值為1。
long int random(void); ? ? ?返回 0 ------- RAND_MAX 之間的一個 long 類型整數,該函數會產生一個非常大的隨機值,最大為 16*((2**31)-1)。
random 函數使用非線性反饋隨機數發生器生成默認大小為31個長整數表所返回的連續偽隨機數。
void srandom(unsigned int seed); ? ? ?設置種子值,一般與“當前時間 + 進程ID”作為種子,如果沒用調用該函數,則通過random返回的默認種子值為1。
上面的這四個函數都是C語言產生隨機數時用到的函數,
如果你使用 srandom 種植種子, 則你應該使用 random 返回隨機數, 如果你使用 srand 種植種子, 則你應該使用rand返回隨機數。
不過srand和rand官方已經不推薦使用。原因是產生隨機數的性能不是很好, 另外是隨機數的隨機性沒有random好, 再者就是不是線程安全。
至于rand的線程不安全,如果你在linux下看過它的源代碼的話,這句話就很容易理解了。
/*
這兩個函數是C庫中產生隨機數的程序。你需要先
使用srand()函數賦隨機數種子值。然后再使用
rand()函數來產生隨機數。但是產生隨機數的算法
較簡單,srandom()和random()函數是對這兩個函數
的改良,用法也很類似。
*/
#define RANDOM_MAX 0x7FFFFFFF
static long my_do_rand(unsigned long *value)
{
/*
這個算法保證所產生的值不會超過(2^31 - 1)
這里(2^31 - 1)就是 0x7FFFFFFF。而 0x7FFFFFFF
等于127773 * (7^5) + 2836,7^5 = 16807。
整個算法是通過:t = (7^5 * t) mod (2^31 - 1)
這個公式來計算隨機值,并且把這次得到的值,作為
下次計算的隨機種子值。
*/
long quotient, remainder, t;
quotient = *value / 127773L;
remainder = *value % 127773L;
t = 16807L * remainder - 2836L * quotient;
if (t <= )
t += 0x7FFFFFFFL;
return ((*value = t) % ((unsigned long)RANDOM_MAX + ));
}
static unsigned long next = ;
int my_rand(void)
{
return my_do_rand(&next);
}
void my_srand(unsigned int seed)
{
next = seed;
}
從代碼中可以清晰的看到,srand()函數是將參數賦值給了一個全局變量,這也是為什么srand()使用int型參數且沒有返回值卻可以影響rand()的值。srand()修改了next的值后,rand()函數可能隱式的調用了該參數(間接調用)??吹竭@里,你就能明白為什么它是線程不安全函數,如果再多線程操作中,一個線程線調用srand,再未完成時另一個線程修改了next則該次操作無意義,這就是基本的多線程編程中的進程的同步與互斥。random()的改進就是基于這一點進行改進。除此之外,我們還可以看到rand()的返回值是基于一個類似于y=ax+b的函數計算出來的。而該表達式中a,b都是常量值,而這里的x就是隨機種子,即通過srand()修改種子。
最后要提的一點是:
假如你想產生 1 ------10 之間的一個隨機數, 建議您像下面這樣編碼
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
而不是下面這樣的代碼
j = 1 + (rand() % 10);
第一行代碼的優勢在于使用實型代替整形,數據是連續的,從而隨機的更均勻,從而提高隨機性。
如果你想要產生1-8的隨機數,j = 1 + (int) (8.0 * (rand() / (RAND_MAX + 1.0))); //即可
1-x: j = 1 + (int) (x.0 * (rand() / (RAND_MAX + 1.0))); //即可
Fisher&ndash;Yates shuffle 洗牌算法(zz)
1,緣起 最近工作上遇到一個問題,即將一組數據,比如[A,B,C,D,E]其中的兩個B,E按隨機排列,其他的仍在原來的位置: 原始數組:[A,B,C,D,E] 隨機字母:[B,D] 可能結果:[A,B ...
由亂序播放說開了去-數組的打亂算法Fisher–Yates Shuffle
之前用HTML5的Audio API寫了個音樂頻譜效果,再之后又加了個播放列表就成了個簡單的播放器,其中弄了個功能是'Shuffle'也就是一般播放器都有的列表打亂功能,或者理解為隨機播放. 但我覺得 ...
洗牌算法shuffle
對這個問題的研究始于一次在群里看到朋友發的洗牌面試題.當時也不知道具體的解法如何,于是隨口回了一句:每次從剩下的數字中隨機一個.過后找相關資料了解了下,洗牌算法大致有3種,按發明時間先后順序如下: 一 ...
random array &; shuffle 洗牌算法 / 隨機算法
random array & shuffle shuffle 洗牌算法 / 隨機算法 https://en.wikipedia.org/wiki/Fisher–Yates_shuffle ES ...
洗牌算法Fisher_Yates原理
1.算法 http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 簡單的原理如下圖所示: 2.原理 總結下,洗牌算法Fisher_Yates ...
js 隨機數 洗牌算法
function shuffle(arr){ var len = arr.length; for(var i = 0;i
knuth洗牌算法
首先來思考一個問題: 設計一個公平的洗牌算法 1. 看問題,洗牌,顯然是一個隨機算法了.隨機算法還不簡單?隨機唄.把所有牌放到一個數組中,每次取兩張牌交換位置,隨機 k 次即可. 如果你的答案是這樣, ...
C# 洗牌算法
最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來. 十年河東十年河西,莫欺少年窮 學無止境,精益求精 ? C#洗牌算法如下: class Program { ...
519. Random Flip Matrix(Fisher-Yates洗牌算法)
1. 問題 給定一個全零矩陣的行和列,實現flip函數隨機把一個0變成1并返回索引,實現rest函數將所有數歸零. 2. 思路 拒絕采樣 (1)先計算矩陣的元素個數(行乘以列),記作n,那么[0, n ...
隨機推薦
(AS3)關于arguments
一.官方說明 點擊訪問 二.使用心得 arguments包含了當前執行方法的參數,注意,不包含默認參數! arguments可以全局訪問,可以在任何方法里訪問,除此之外,在定義變量的時候或者初始化的時 ...
jquery常用正則表達式
1.郵箱驗證正則表達式:/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/ 2.手機驗證正則表達式:/^ ...
radio checked不起作用的原因
| Servlet工作原理 Servlet生命周期分為三個階段: 1,初始化階段? 調用init()方法 2,響應客戶請求階段 調用service()方法 3,終止階段 調用destroy()方法 Servlet初始化階段: 在 ... poj 2976 Dropping tests http://poj.org/problem?id=2976 這道題就是從n個a[i]和b[i]中去掉k個a[i]和[i]使得.最大. #include #include ... sqlplus登錄Oracle時ORA-01017: invalid username/password; logon denied的錯誤 今天用scott用戶登錄Oracle數 據庫時,竟然出現了ORA-01017: invalid username/password; logon denied錯誤,原以為是因為我的scott用戶沒有解 ... C#面向對象(1) 一.面向對象(OOP) 面向過程 面向過程就是分析出解決問題的所需要的步驟,然后每個步驟使用函數實現,使用時將函數依次調用即可 C語言 面向對象 對象:生活中真實存在的事物(電腦.手機.草.樹.... ... 山西大同大學教務處學生端--送給學弟,學妹的禮物,可在PC端,手機端操作 解決問題:大同大學教務處官網學生端口一進去就卡住了,點上面一行的菜單無響應 轉眼已是四年,想想自己大學即將結束,不由得讓人感慨啊.這才剛開學幾天,我就聽到有同學在因為補考,選課的事情發愁.學校官方的教 ... k8s的使用 . 查看 kubectl 的狀態 kubectl version . 查看集群信息 kubectl cluster-info . 查看節點信息 kubectl get nodes . 創建一個發布 k ... |
總結
以上是生活随笔為你收集整理的洗牌复原次数c语言公式,洗牌算法Fisher-Yates以及C语言随机数的产生的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html网页漂浮广告原理js,JS实现弹
- 下一篇: G网和C网