隨筆-159  評(píng)論-114  文章-7  trackbacks-0
          這個(gè)需求應(yīng)該是很常見(jiàn)的吧,需要從 0 到 n 之間選 k 個(gè)不重復(fù)的數(shù)組成一個(gè)序列。

          我最早遇到這個(gè)問(wèn)題是在給校ACM比賽出題時(shí),需要隨機(jī)產(chǎn)生一些測(cè)試數(shù)據(jù),當(dāng)時(shí)我想的是用一個(gè)輔助數(shù)組記錄之前已經(jīng)產(chǎn)生的隨機(jī)數(shù),如果當(dāng)前產(chǎn)生的隨機(jī)數(shù)已經(jīng)出現(xiàn)過(guò)就再重新隨機(jī)

          顯然這樣的實(shí)現(xiàn)效率是很低的,設(shè)想從10000個(gè)數(shù)隨機(jī)產(chǎn)生10000個(gè)數(shù)的序列,當(dāng)前面9999個(gè)數(shù)已經(jīng)確定了時(shí),最后一個(gè)數(shù)隨機(jī)到的概率是 0.0001,也就是說(shuō)大概需要調(diào)用隨機(jī)函數(shù)10000才會(huì)產(chǎn)生。類似的,第9999個(gè)數(shù)隨機(jī)到的概率是0.0002……
          .....

          我后來(lái)采用了一個(gè)改進(jìn)的辦法是,如果當(dāng)前產(chǎn)生的隨機(jī)數(shù)a已經(jīng)在之前產(chǎn)生過(guò)了,就順序去找比a小的數(shù),直到找到一個(gè)之前沒(méi)有產(chǎn)生過(guò)的數(shù),如果找不到就找比a大的數(shù)

          可以看到這樣的改進(jìn)節(jié)省了大量的時(shí)間,但是這樣產(chǎn)生的已經(jīng)不是隨機(jī)數(shù)序列了!

          試想從1,2,3,4中隨機(jī)挑選2個(gè)數(shù),假如第一次選出來(lái)的是3,那么第二再選的話,選中2的概率就變成了1/2,因?yàn)楫?dāng)隨機(jī)出來(lái)的數(shù)為2或3時(shí),我們都選擇2。

          在我遇到的應(yīng)用中,因?yàn)閷?duì)隨機(jī)數(shù)序列的“隨機(jī)性”要求不是很高,所以湊合著用了上述辦法。

          直到今天在《Programming pearls》里看到這個(gè)很完美的辦法:
          for(i = 0; i < n; i++)
          {
          x[i] = i;
          }
          for(i = 0; i < k; i++)
          {
          t = rand(i,n-1);
          swap(x[i], x[t]);
          out(x[i]);
          }

          其中,rand(a,b)產(chǎn)生一個(gè) a 到 b 之間的隨機(jī)數(shù),swap(a,b)交換a和b的值,out(a)把a(bǔ)輸出作為結(jié)果。
          我們來(lái)看看這個(gè)算法的完美之處吧!

          首先,x數(shù)組里把0到n-1的所有數(shù)都存儲(chǔ)了,而最后輸出的都是x數(shù)組里的值,所以滿足輸出的數(shù)是k個(gè)0到n-1的數(shù)

          然后,我們對(duì)于第 i 隨機(jī),產(chǎn)生一個(gè) i 到 n-1 的下標(biāo) t ,并把x[t] 和x[i]交換,將其輸出,這樣每產(chǎn)生的數(shù)都是之前沒(méi)有出現(xiàn)過(guò)的數(shù),因?yàn)橹俺霈F(xiàn)過(guò)的數(shù)都在x[0] 到 x[i-1]里呢!這樣就保證了輸出數(shù)據(jù)的不重復(fù)性。

          最后,我們考察輸出數(shù)據(jù)的“隨機(jī)性”,顯然,因?yàn)榻粨Q操作,使得所有沒(méi)有出現(xiàn)過(guò)的數(shù)都在x[i] 到 x[n-1]中存著呢,所以被選中的概率相等。


          寫完上面這些文字之后,我在想,這樣經(jīng)典的算法,應(yīng)該是早就已經(jīng)出現(xiàn)了,但是我竟然還不知道,這樣看來(lái),我百度實(shí)習(xí)面試遭鄙視也就是很自然的了,這也算是我之前的一個(gè)毛病,喜歡遇到問(wèn)題才去想怎么解決,沒(méi)問(wèn)題就很少看相關(guān)的書或資料,而對(duì)于自己能解決的問(wèn)題(比如上面說(shuō)的這個(gè)湊合著能用的問(wèn)題),我又懶得去找更好的甚或是標(biāo)準(zhǔn)的解決方法,所以才造成了我現(xiàn)在的知識(shí)局限,以后要多看書,多想問(wèn)題,盡量多的積累知識(shí)吧……


          posted on 2010-02-21 14:21 北國(guó)狼人的BloG 閱讀(4137) 評(píng)論(1)  編輯  收藏

          評(píng)論:
          # re: 高效產(chǎn)生一組不重復(fù)的隨機(jī)數(shù) 2013-08-12 18:11 | ll
          要是要求產(chǎn)生的隨機(jī)數(shù)量特別大怎么辦啊  回復(fù)  更多評(píng)論
            

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 水城县| 汝城县| 天水市| 思茅市| 佛山市| 于都县| 香格里拉县| 天台县| 泾源县| 北票市| 兴安盟| 乐清市| 新密市| 梅州市| 武汉市| 孟村| 桓仁| 和龙市| 峨山| 甘谷县| 武隆县| 当雄县| 巨野县| 汤阴县| 安国市| 威远县| 上思县| 高清| 衡阳市| 兰坪| 伊川县| 横山县| 梨树县| 民权县| 中超| 九龙城区| 双牌县| 遂平县| 大冶市| 泸水县| 六盘水市|