算法練習(xí)(110): 亂序檢查(1.1.36)

知識(shí)點(diǎn)

  • 洗牌算法
  • 隨機(jī)數(shù)

1.1.36 亂序檢查。通過(guò)實(shí)驗(yàn)檢查表1.1.10 中的亂序代碼是否能夠產(chǎn)生預(yù)期的效果。編寫(xiě)一個(gè)程序ShuffleTest,接受命令行參數(shù)M 和N,將大小為M 的數(shù)組打亂N 次且在每次打亂之前都將數(shù)組重新初始化為a[i] = i。打印一個(gè)M×M 的表格,對(duì)于所有的列j,行i 表示的是i 在打亂后落到j(luò) 的位置的次數(shù)。數(shù)組中的所有元素的值都應(yīng)該接近于N/M。


1.1.36 Empirical shuffle check. Run computational experiments to check that our shuffling code on page 32 works as advertised. Write a program ShuffleTest that takes command-line arguments M and N, does N shuffles of an array of size M that is initialized with a[i] = i before each shuffle, and prints an M-by-M table such that row i gives the number of times i wound up in position j for all j. All entries in the array should be close to N/M.

分析

表1.1.10 中的亂序代碼如下:

public static void shuffle(double[] a)
{
   int N = a.length;
   for (int i = 0; i < N; i++)
   {  // Exchange a[i] with random element in a[i..N-1]
      int r = i + StdRandom.uniform(N-i);
      double temp = a[i];
      a[i] = a[r];
      a[r] = temp;
    } 
}

下面我們來(lái)分析一下shuffle這個(gè)單詞

shuffle
英 ['??f(?)l] 美 ['??fl]
v. 洗牌;推諉,推卸;拖曳,慢吞吞地走;攪亂
n. 洗牌,洗紙牌;混亂,蒙混;拖著腳走

其實(shí)關(guān)于洗牌算法有很多,大概百度一下可以看到如下算法:

Fisher–Yates shuffle 洗牌算法

Fisher–Yates shuffle 算法是一個(gè)用來(lái)將一個(gè)有限集合生成一個(gè)隨機(jī)排列的算法(數(shù)組隨機(jī)排序)。這個(gè)算法生成的隨機(jī)排列是等概率的。同時(shí)這個(gè)算法非常高效。
Fisher and Yates 的原始版
Fisher–Yates shuffle 的原始版本,最初描述在 1938 年的 Ronald Fisher(上圖) 和 Frank Yates 寫(xiě)的書(shū)中,書(shū)名為《Statistical tables for biological, agricultural and medical research》。他們使用紙和筆去描述了這個(gè)算法,并使用了一個(gè)隨機(jī)數(shù)表來(lái)提供隨機(jī)數(shù)。它給出了 1 到 N 的數(shù)字的的隨機(jī)排列,具體步驟如下:

  • 寫(xiě)下從 1 到 N 的數(shù)字
  • 取一個(gè)從 1 到剩下的數(shù)字(包括這個(gè)數(shù)字)的隨機(jī)數(shù) k
  • 從低位開(kāi)始,得到第 k 個(gè)數(shù)字(這個(gè)數(shù)字還沒(méi)有被取出),把它寫(xiě)在獨(dú)立的一個(gè)列表的最后一位
  • 重復(fù)第 2 步,直到所有的數(shù)字都被取出
  • 第 3 步寫(xiě)出的這個(gè)序列,現(xiàn)在就是原始數(shù)字的隨機(jī)排列

已經(jīng)證明如果第 2 步取出的數(shù)字是真隨機(jī)的,那么最后得到的排序一定也是。
現(xiàn)代方法
Fisher–Yates shuffle 算法的現(xiàn)代版本是為計(jì)算機(jī)設(shè)計(jì)的。由 Richard Durstenfeld 在1964年 描述。并且是被 Donald E. Knuth 在 《The Art of Computer Programming》 中推廣。但是不管是 Durstenfeld 還是 Knuth,都沒(méi)有在書(shū)的第一版中承認(rèn)這個(gè)算法是 Fisher 和 Yates 的研究成果。也許他們并不知道。不過(guò)后來(lái)出版的 《The Art of Computer Programming》提到了 Fisher 和 Yates 貢獻(xiàn)。
現(xiàn)代版本的描述與原始略有不同,因?yàn)槿绻凑赵挤椒ǎ薮赖挠?jì)算機(jī)會(huì)花很多無(wú)用的時(shí)間去計(jì)算上述第 3 步的剩余數(shù)字。這里的方法是在每次迭代時(shí)交換這個(gè)被取出的數(shù)字到原始列表的最后。這樣就將時(shí)間復(fù)雜度從 O(n^2) 減小到了 O(n)。

inside-out算法

是一種重新檢驗(yàn)隨機(jī)上下文無(wú)關(guān)文法(probabilistic context-free grammar)生成幾率的方式,由James K. Baker 於1979年提出,是一個(gè)一般化的向前向後演算法,用來(lái)作為隨機(jī)上下文無(wú)關(guān)文法其隱馬爾可夫模型的屬性評(píng)估。這種演算法是用來(lái)計(jì)算某種期望值,舉例來(lái)說(shuō),可以用來(lái)成為最大期望算法(一種無(wú)監(jiān)督的學(xué)習(xí)演算法)的一部分。

最后給出兩種算法的代碼實(shí)現(xiàn):

見(jiàn)小專欄算法練習(xí)(15):驗(yàn)證洗牌算法的正確性(1.1.36)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 回溯算法 回溯法:也稱為試探法,它并不考慮問(wèn)題規(guī)模的大小,而是從問(wèn)題的最明顯的最小規(guī)模開(kāi)始逐步求解出可能的答案,并...
    fredal閱讀 13,993評(píng)論 0 89
  • 告別過(guò)去,擁抱未來(lái)。 做一個(gè)美好而又努力的人,做一個(gè)光明磊落而又大膽的人。
    上邪不邪閱讀 259評(píng)論 2 0
  • 一些很奇怪的人。 晚間接到?,毀了一晚上的好心情…真心忍不住要曝光這么一件事情。是的,短短二十分鐘的對(duì)話,忍住了三...
    唐嬪閱讀 281評(píng)論 0 0
  • 羅列看著身患重病的方穎,心里像打翻了五味瓶,酸甜苦辣涌上心頭,往事一幕幕的浮現(xiàn)在眼前。 一 “黑頭發(fā)飄起來(lái),飄起來(lái)...
    西嶺布衣閱讀 300評(píng)論 2 8
  • 認(rèn)識(shí)一個(gè)姑娘A,機(jī)靈活潑,反駁別人的時(shí)候嘴皮子溜得厲害,見(jiàn)誰(shuí)的面都熱情地打招呼,喜歡誰(shuí)無(wú)論男的女的都可以嘴里叫著親...
    看過(guò)星星的兔子閱讀 322評(píng)論 1 0

友情鏈接更多精彩內(nèi)容