算法S

        百度百科裏面是這麼解釋算法的:算法可以理解爲有基本運算及規定的運算順序所構成的完整的解題步驟。或者看成按照要求設計好的有限的確切的計算序列,並且這樣的步驟和序列可以解決一類問題。算法我們也學過不少了《數據結構》裏面講到的字符串匹配算法,排序算法等等但近日遇到的這個S算法,讓我很是驚歎一種說不出的精妙。

       近日遇到的一個問題,從N個數裏面隨機抽取M個不同的數,並且這M個數是有序的。於是想是《編程珠璣裏面的取樣問題章節提到的S算法,順利地解決了問題,重新看了一下這個算法,覺得甚是奇妙。

      書上的問題是這樣的:程序的輸入包含兩個整數m和n,其中m <n。輸出是0~n-1範圍內的m個隨機整數的有序列表,不允許重複。從概率的角度講,我們希望得到沒有重複的有序選擇,其中每個選擇出現的概率相等。

爲了說明的需要,這裏的n直接取[0,n)範圍內的整數

Python算法實現:

import random
 def getknuth(m,n):
	for i in range(n):
		a = random.randint(0,n-i-1)
		#print "a is %d,m is %d"%(a,m)
		if( a < m):
			print i
			m -= 1

getknuth(3,5)

C語言算法實現如下:

for(i=0;i < n;i++)
 {
	a=rand() % (n - i);
	if(a < m){
		printf("%d ",i);
		m--;
	}
 }

這個算法的精妙之處在於算法中隨機得到的數是a,但真正爲我們所需要的卻是i(當時剛看這個算法的時候,一直覺得a才是要求的隨機數,怎麼會輸出i呢?妙哉妙哉),這樣解決了隨機的問題,也保證了有序,一個算法同時解決了兩個問題,真是妙。

我們假設這裏的m=10,n=20,最壞的情況,在for循環的前10次,隨機數a(10……19),均不小於10,不滿足條件a < m,這時i爲9,於是第11次循環時,i的值爲10,於是rand()%10必定在[0,9]裏面,必定滿足條件a<m,於是得到滿足我們條件的第一個數即爲i的值:10,於是m1變成9,在做第12次循環時,i爲11,rand()%9必定在[0,8]範圍內,也滿足a<m,滿足我們條件的第二個數爲:11,依次類推,我們將會得到12……19,於是,這m個數即爲數列[10,19],隨機且有序。

這是最壞的情況,也就是說爲得到m個不同的隨機數,時間複雜度爲O(n);

其實這個算法來源於Knuth的《計算機程序設計藝術》(第2卷)3.4.2節的算法S,這裏要說明一下,n中每個數被選中的概是均等的,Knuth在書中給出了數學上的證明(據說這個算法是解決此類問題到目前爲止最高效的算法)。

數學一直是我的短板,對於這個算法,目前只能從程序上體會它的精妙,在數學上,還不能理解通透。









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章