編程珠璣–第12章 取樣問題

來源:互聯網
上載者:User

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

討論這些問題前有兩個假設:1.有一個函數bigrand()能夠返回很大的隨機整數(遠遠大於m和n)。

   
         2.另一個函數randint(i,j)能夠返回i..j範圍內均勻選擇的隨機整數。

解法一:假設m=2,n=5,選擇第一個數0的機率為2/5,可以通過以下語句來實現:if(bigrand()%5)<2,<2也就是只能取0或者1,表示了機率為2/5。但是當我們選擇1的時候,要根據前面是否選擇了0。如果選擇了0,則按照1/4的機率選擇1,而未選擇0的情況下按照2/4的機率選擇1,以此類推。當m=n的時候,一定能夠被選中(因為bigrand()%m<n(m)一定是成立的)。

select=mremaining=nfor i=[0,n)if(bigrand()%remaining)<selectprint iselect--remaining--

分析:這裡我們是遍曆[0,n),然後用機率選擇,如果選中了select和remaining都要減1,如果沒有選中remaining減1。當select減少到0的時候程式雖然在運行,但是已經不可能再選中了,所以可以修改一下程式當select減少為0的時候跳出。Knuth給出了證明,每個子集被選中的可能性是相等的。

c++實現:

void getknuth(int m,int n){for(int i=0;i<n;i++)if((bigrand()%(n-i))<m){cout<<i<<"\n";m--;}}

解法二:在一個初始為空白的集合裡面插入隨機整數,直到個數足夠。我們這裡使用c++ stl中的set來實現。

set是一個容器,它其中包含的元素值是唯一的。比如我們以下面這段程式說明:

#include<iostream>#include<set>using namespace std;int main(){set<int> s;s.insert(3);s.insert(3);cout<<s.size();return 0;}

輸出的值是1,若相同的話set選擇不插入。

void getsets(int m,int n){set<int> S;while(S.size()<m)S.insert(bigrand()%n);set<int>::iterator i;for(i=S.begin();i!=S.end();++i)cout<<*i<<endl;}

解法三:把包含0~n-1的數組順序打亂,然後把前m個元素排序輸出。

void genshuf(int m,int n){int i,j;int *x=new int[n];for(i=0;i<n;i++)x[i]=i;for(i=0;i<m;i++){j=randint(i,n-1);int t=x[i];x[i]=x[j];x[j]=t;}sort(x,x+m);for(i=0;i<m;i++)cout<<x[i]<<endl;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.