2008-10-01 19 views
28

के बीच के गैर-दोहराने वाले पूर्णांक की सूची कैसे कुशलतापूर्वक उत्पन्न करते हैं प्रश्न यह आवश्यक डेटा देता है: के अनुक्रम उत्पन्न करने के लिए एक कुशल एल्गोरिदम क्या है जो किसी दिए गए भीतर पूर्ण न हो अंतराल [0, एन -1]। तुच्छ एल्गोरिदम (यादृच्छिक संख्याएं उत्पन्न करना, उन्हें अनुक्रम में जोड़ने से पहले, उन्हें देखने के लिए देख रहे हैं कि वे पहले से मौजूद हैं या नहीं) के बहुत महंगा है और एन पर पर्याप्त है।आप 0 और ऊपरी बाउंड एन

Efficiently selecting a set of random elements from a linked list में प्रदान किया गया एल्गोरिदम आवश्यक से अधिक जटिल लगता है, और कुछ कार्यान्वयन की आवश्यकता है। मुझे एक और एल्गोरिदम मिला है जो कि नौकरी ठीक करने लगता है, जब तक आप एक ही पास में सभी प्रासंगिक मानकों को जानते हैं।

+0

रुको, अगर आपको पहले से ही एक और एल्गोरिदम मिला है, तो सवाल क्या है? –

+1

इस तरह के एक साफ एल्गोरिदम! इसे किसी के साथ साझा करना था - और ऐसा लगता है कि http://stackoverflow.com/faq के अनुसार व्यवहार की अनुशंसा की जाती है: "यह आपके प्रोग्रामिंग प्रश्न पूछने और जवाब देने के लिए भी बिल्कुल ठीक है, लेकिन नाटक करें कि आप Jeopardy – tucuxi

+1

उत्तर पर हैं यह मेरे लिए सबसे अच्छा लग रहा है। http://stackoverflow.com/questions/2394246/algorithm-to-select-a-single-random-combination-of-values ​​ – Fakrudeen

उत्तर

12

random module अजगर पुस्तकालय से यह बहुत आसान और प्रभावी बनाता है:

from random import sample 
print sample(xrange(N), K) 

sample समारोह कश्मीर अद्वितीय दिया अनुक्रम में से चुना तत्वों की सूची देता है।
xrange एक "सूची एमुलेटर" है, यानी यह स्मृति में इसे बनाए बिना लगातार संख्याओं की एक सूची की तरह व्यवहार करता है, जो इसे इस तरह के कार्यों के लिए सुपर-फास्ट बनाता है।

+5

पायथन कार्यान्वयन काफी अच्छा है (http://svn.python.org/view/python/trunk/Lib/random.py?view=markup देखें, "नमूना" के लिए खोजें)। वे दो मामलों में अंतर करते हैं, एक बड़े के (एन के पास के) और एक छोटे के के लिए एक। बड़े के लिए, वे चुनिंदा तत्वों की प्रतिलिपि बनाते हैं। छोटे के लिए, वे एक सेट का उपयोग करके पुनरावृत्ति से परहेज करते हुए, तत्वों को यादृच्छिक रूप से आकर्षित करते हैं। – tucuxi

+2

यह बड़े अनुक्रमों के लिए स्मृति में अक्षम है। –

+0

https://hg.python.org/cpython/file/tip/Lib/random.py नया स्रोत लिंक है। –

1

हैशिंग स्टोर में के नंबरों को संग्रहीत करके छोटे एल्गोरिदम को गति दें। शुरू करने से पहले के बारे में जानना एक हैश मानचित्र में डालने की सभी अक्षमता को दूर करता है, और आपको अभी भी तेजी से दिखने का लाभ मिलता है।

+1

हाँ, वह जिस तरह से मैंने लॉटरी – axk

+0

लॉटरी के लिए 10 एम अपरिपक्व यादृच्छिक संख्या की आवश्यकता नहीं थी, बहुत मेमोरी-कुशल नहीं - एक के आकार की सहायक संरचना की आवश्यकता है। समय में, आपको के सम्मिलन और एन निष्कासन की आवश्यकता होती है। मुझे प्राप्त एल्गोरिदम केवल (केवल सबसे अधिक) के यादृच्छिक ड्रॉ। – tucuxi

+0

आपको एक सहायक संरचना की आवश्यकता नहीं है। बस मानचित्र को अपनी एकमात्र संरचना बनाएं। के आइटम को स्टोर करने के लिए आपको हमेशा के सम्मिलन की आवश्यकता होगी। आपको एन निकासी की आवश्यकता क्यों है? –

3

निम्नलिखित कोड (सी, अज्ञात मूल में) समस्या को हल करने बहुत अच्छी तरह से लगता है:

/* generate N sorted, non-duplicate integers in [0, max[ */ 
int *generate(int n, int max) { 
    int i, m, a;  
    int *g = (int *)calloc(n, sizeof(int)); 
    if (! g) return 0; 

    m = 0; 
    for (i=0; i<max; i++) { 
     a = random_in_between(0, max - i); 
     if (a < n - m) { 
      g[m] = i; 
      m ++; 
     } 
    } 
    return g; 
} 

किसी को भी पता है, जहां मैं इस तरह अधिक जवाहरात मिल सकती है?

+2

जॉन बेंटले द्वारा प्रोग्रामिंग मोती ("रत्न" पर पन जानबूझकर था)। :) –

+0

"random_in_between" के लिए क्या खड़ा है? –

+2

यह एल्गोरिदम एक बड़े सेट से चुने गए छोटे नमूने के लिए बहुत अक्षम है। एक मिलियन से 5 पूर्णांक चुनने से 5 लाख की बजाय रैंड() के लिए एक लाख कॉल लेते हैं। –

2

0...N-1a[i] = i भरने वाला एक सरणी उत्पन्न करें।

फिर पहले K आइटम को घुमाएं।

फेरबदल:

  • प्रारंभ J = N-1
  • एक यादृच्छिक संख्या 0...J (जैसे कि, R)
  • a[J]
    • साथ स्वैप a[R] उठाओ के बाद से RJ के बराबर हो सकता है, तत्व हो सकता है खुद के साथ स्वैप किया जा सकता है
  • 1J से घटाएं और दोहराएं।

अंत में, K अंतिम तत्व लें।

यह अनिवार्य रूप से सूची से यादृच्छिक तत्व चुनता है, इसे बाहर ले जाता है, फिर शेष सूची से यादृच्छिक तत्व चुनता है, और इसी तरह। हे (के) और हे (एन) समय में

काम करता है, हे (एन) भंडारण की आवश्यकता है।

फेरबदल हिस्सा Fisher-Yates shuffle या नुथ के फेरबदल, आर्ट ऑफ़ कंप्यूटर प्रोग्रामिंग के 2 मात्रा में वर्णित कहा जाता है।

+0

आपका दृष्टिकोण [0, एन [] में क्रमपरिवर्तन उत्पन्न करने के लिए ठीक है, लेकिन मुझे सीमा में संख्याएं चाहिए [0, के [। उदाहरण के लिए, यदि एन = 2 और के = 10, {5, 9} एक मान्य आउटपुट अनुक्रम है। – tucuxi

+0

फिर 0 .. के उत्पन्न करें, और उसके बाद संख्याएं यादृच्छिक रूप से हटाएं जब तक आपके पास एन संख्या न हो। –

+0

यह समान रूप से यादृच्छिक नहीं है: चूंकि 'जे' को एक बार 'के [जे]' से दूर ले जाया गया है, इसकी एक अलग संभावना है। जैसे 'के = 1' के साथ,' एन -1 'कभी नहीं चुना जा सकता है। –

-2

यह पर्ल कोड है। Grep एक फ़िल्टर है, और हमेशा के रूप में मैंने इस कोड का परीक्षण नहीं किया था।

@list = grep ($_ % I) == 0, (0..N); 
  • मैं = अंतराल
  • एन = ऊपरी बाध्य

केवल संख्याओं कि मापांक ऑपरेटर के माध्यम से अपने अंतराल से मेल मिलता है।

@list = grep ($_ % 3) == 0, (0..30); 

वापस आ जाएगी 0, 3, 6, ... 30

यह छद्म पर्ल कोड है। इसे संकलित करने के लिए आपको इसे ट्विक करने की आवश्यकता हो सकती है।

+0

यह निर्दिष्ट कार्य निष्पादित नहीं करता प्रतीत होता है। –

0

जलाशय का नमूना लेना संस्करण बहुत सरल है:

my $N = 20; 
my $k; 
my @r; 

while(<>) { 
    if(++$k <= $N) { 
    push @r, $_; 
    } elsif(rand(1) <= ($N/$k)) { 
    $r[rand(@r)] = $_; 
    } 
} 

print @r; 

stdin से $ एन बेतरतीब ढंग से चुनी हुई पंक्तियां है यही कारण है कि। यदि आप किसी फ़ाइल से पंक्तियों का उपयोग नहीं कर रहे हैं, तो <>/$ _ सामान को किसी और चीज़ से बदलें, लेकिन यह एक बहुत सीधा एल्गोरिदम है।

-1

यहाँ अतिरिक्त भंडारण के बिना हे (एन) में यह करने के लिए एक तरीका है। मुझे पूरा यकीन है कि यह पूरी तरह से यादृच्छिक वितरण नहीं है, लेकिन यह संभवतः कई उपयोगों के लिए पर्याप्त है।

/* generate N sorted, non-duplicate integers in [0, max[ in O(N))*/ 
int *generate(int n, int max) { 
    float step,a,v=0; 
    int i;  
    int *g = (int *)calloc(n, sizeof(int)); 
    if (! g) return 0; 

    for (i=0; i<n; i++) { 
     step = (max-v)/(float)(n-i); 
     v+ = floating_pt_random_in_between(0.0, step*2.0); 
     if ((int)v == g[i-1]){ 
      v=(int)v+1;    //avoid collisions 
     } 
     g[i]=v; 
    } 
    while (g[i]>max) { 
     g[i]=max;     //fix up overflow 
     max=g[i--]-1; 
    } 
    return g; 
} 
0

मेरे समाधान सी ++ उन्मुख है, लेकिन मुझे यकीन है कि यह अन्य भाषाओं में अनुवाद किया जा सकता है, क्योंकि यह बहुत आसान है हूँ।

  • पहले, कश्मीर तत्वों के साथ एक लिंक की गई सूची, 0 से कश्मीर
  • के लिए जा रहा तो फिर जब तक सूची खाली नहीं है, 0 के बीच एक यादृच्छिक संख्या और वेक्टर के आकार उत्पन्न उत्पन्न
  • उस तत्व को ले लो, इसे किसी अन्य वेक्टर में दबाएं, और इसे मूल सूची से हटा दें

इस समाधान में केवल दो लूप पुनरावृत्तियों, और कोई हैश टेबल लुकअप या सॉर्ट नहीं है। तो वास्तविक कोड में:

// Assume K is the highest number in the list 
std::vector<int> sorted_list; 
std::vector<int> random_list; 

for(int i = 0; i < K; ++i) { 
    sorted_list.push_back(i); 
} 

// Loop to K - 1 elements, as this will cause problems when trying to erase 
// the first element 
while(!sorted_list.size() > 1) { 
    int rand_index = rand() % sorted_list.size(); 
    random_list.push_back(sorted_list.at(rand_index)); 
    sorted_list.erase(sorted_list.begin() + rand_index); 
}     

// Finally push back the last remaining element to the random list 
// The if() statement here is just a sanity check, in case K == 0 
if(!sorted_list.empty()) { 
    random_list.push_back(sorted_list.at(0)); 
} 
5

यह वास्तव में संभव नहीं बल्कि सेट आप से चयन किए जाने वाले के आकार की तुलना चयनित अंतरिक्ष तत्वों की संख्या के लिए आनुपातिक में ऐसा करने के लिए, भले ही कुल सेट का कितना अनुपात है आप चुन रहे हैं आप यादृच्छिक क्रमपरिवर्तन उत्पन्न करके ऐसा करते हैं, फिर इसे इस तरह से चुनते हैं:

TEA या XTEA जैसे ब्लॉक साइफर चुनें। ब्लॉक आकार को उस सेट से दो बड़े की छोटी शक्ति तक कम करने के लिए XOR folding का उपयोग करें, जिसे आप चुन रहे हैं। सिफर के लिए कुंजी के रूप में यादृच्छिक बीज का प्रयोग करें। क्रमपरिवर्तन में तत्व n उत्पन्न करने के लिए, सिफर के साथ एन एन्क्रिप्ट करें। यदि आउटपुट नंबर आपके सेट में नहीं है, तो उसे एन्क्रिप्ट करें। सेट के अंदर संख्या होने तक दोहराएं।औसतन आपको प्रति उत्पन्न संख्या से कम दो एन्क्रिप्शन करना होगा। इसमें अतिरिक्त लाभ है कि यदि आपका बीज क्रिप्टोग्राफ़िक रूप से सुरक्षित है, तो आपका पूरा क्रमपरिवर्तन भी है।

मैं और अधिक विस्तार here में इस बारे में लिखा था।

+0

अच्छा लेख। लेकिन, "एक्सओआर फोल्डिंग" विशिष्टता को नष्ट नहीं करता है? निश्चित रूप से, x! = Y काम करने के लिए डीकोडिंग के लिए encipher (x)! = Encipher (y) का तात्पर्य है, लेकिन उदाहरण का उपयोग (Encipher (x) >> 4)^(Encipher (x) और MASK) इसके बजाय एक ही कोड पर अलग-अलग x मानों को "पतन" कर सकता है - इसलिए आपके "क्रमपरिवर्तन" में दोहराना हो सकता है। –

+0

मेरे पास सैद्धांतिक आधार नहीं है, लेकिन नहीं, यह ब्लॉक साइफर के 1-से-1 मैपिंग गुणों को नष्ट नहीं करता है। ज़ोर फोल्डिंग टीईए सिफर से ली जाती है - शायद अधिक जानकारी के लिए उस पर संदर्भों की जांच करें। –

+0

@j_random_hacker: बेशक, आप सही हैं। लेकिन फिर भी कुछ क्रिप्टोग्राफ़िक हैश फ़ंक्शन का उपयोग करके एक कस्टम फीस्टल सिफर का उपयोग करके एक छद्म यादृच्छिक क्रमपरिवर्तन के साथ आने के लिए यह संभव है कि फ़ंक्शन F. – sellibitze

10

The Art of Computer Programming, Volume 2: Seminumerical Algorithms, Third Edition में, नुथ का वर्णन निम्नलिखित चयन नमूना एल्गोरिथ्म:

एल्गोरिथ्म एस (चयन नमूना तकनीक)। एन का एक सेट है, जहां 0 < n ≤ एन

एस 1 से यादृच्छिक पर n रिकॉर्ड का चयन करें। [आरंभ करें।] टी सेट करें 0 0, एम ← 0. (इस एल्गोरिदम के दौरान, एम अब तक चुने गए रिकॉर्ड्स की संख्या का प्रतिनिधित्व करता है, और टी इनपुट इनपुट रिकॉर्ड की कुल संख्या है जिसे हमने निपटाया है।)

एस 2। [यू उत्पन्न करें] एक यादृच्छिक संख्या यू उत्पन्न करें, समान रूप से शून्य और एक के बीच वितरित।

S3। [टेस्ट।] यदि (एन - टी) यू ≥ एन - एम, चरण S5 पर जाएं।

एस 4। [चुनें।] नमूना के लिए अगला रिकॉर्ड चुनें, और एम और टी को 1 तक बढ़ाएं। यदि एम < एन, चरण S2 पर जाएं; अन्यथा नमूना पूरा हो गया है और एल्गोरिदम समाप्त हो जाता है।

S5। [छोड़ें।] अगला रिकॉर्ड छोड़ें (इसे नमूना में शामिल न करें), 1 से टी बढ़ाएं, और चरण S2 पर वापस जाएं।

वर्णन से अधिक कार्यान्वयन करना आसान हो सकता है।

(defun sample-list (n list &optional (length (length list)) result) 
    (cond ((= length 0) result) 
     ((< (* length (random 1.0)) n) 
     (sample-list (1- n) (cdr list) (1- length) 
         (cons (car list) result))) 
     (t (sample-list n (cdr list) (1- length) result)))) 

और यहाँ एक कार्यान्वयन कि प्रत्यावर्तन का उपयोग नहीं करता है, और जो दृश्यों के सभी प्रकार के साथ काम करता है:: यह एक कॉमन लिस्प कार्यान्वयन कि एक सूची से n यादृच्छिक सदस्यों का चयन है

(defun sample (n sequence) 
    (let ((length (length sequence)) 
     (result (subseq sequence 0 n))) 
    (loop 
     with m = 0 
     for i from 0 and u = (random 1.0) 
     do (when (< (* (- length i) u) 
        (- n m)) 
      (setf (elt result m) (elt sequence i)) 
      (incf m)) 
     until (= m n)) 
    result)) 
+0

आधिकारिक उत्तर के लिए धन्यवाद। मेरे पास एक ही आवश्यकता है, और यह वह अहंकार है जिसे मैं लागू करने की योजना बना रहा हूं। एक बार फिर धन्यवाद। – sundar

0

हैं सूची क्रमबद्ध किया जाता है, उदाहरण के लिए, यदि आप एन से बाहर कश्मीर तत्वों निकालना चाहते हैं, लेकिन आप अपने रिश्तेदार आदेश के बारे में परवाह नहीं है, एक कुशल एल्गोरिथ्म कागज An Efficient Algorithm for Sequential Random Sampling (जेफरी स्कॉट Vitter में प्रस्तावित है, गणितीय सॉफ्टवेयर पर एसीएम लेन-देन , खंड 13, संख्या 1, मार्च 1 9 87, पृष्ठ 56-67।)।

संपादित करने के लिए C++ में कोड जोड़ने के लिए संपादित किया गया। मैंने अभी इसे टाइप किया है और कई त्रुटियां हो सकती हैं। यादृच्छिक संख्या बूस्ट लाइब्रेरी से एक बेवकूफ बीज के साथ आती है, इसलिए इसके साथ कुछ भी गंभीर मत करो।

/* Sampling according to [Vitter87]. 
* 
* Bibliography 
* [Vitter 87] 
* Jeffrey Scott Vitter, 
* An Efficient Algorithm for Sequential Random Sampling 
* ACM Transactions on MAthematical Software, 13 (1), 58 (1987). 
*/ 

#include <stdlib.h> 
#include <string.h> 
#include <math.h> 
#include <string> 
#include <iostream> 

#include <iomanip> 

#include <boost/random/linear_congruential.hpp> 
#include <boost/random/variate_generator.hpp> 
#include <boost/random/uniform_real.hpp> 

using namespace std; 

// This is a typedef for a random number generator. 
// Try boost::mt19937 or boost::ecuyer1988 instead of boost::minstd_rand 
typedef boost::minstd_rand base_generator_type; 

    // Define a random number generator and initialize it with a reproducible 
    // seed. 
    // (The seed is unsigned, otherwise the wrong overload may be selected 
    // when using mt19937 as the base_generator_type.) 
    base_generator_type generator(0xBB84u); 
    //TODO : change the seed above ! 
    // Defines the suitable uniform ditribution. 
    boost::uniform_real<> uni_dist(0,1); 
    boost::variate_generator<base_generator_type&, boost::uniform_real<> > uni(generator, uni_dist); 



void SequentialSamplesMethodA(int K, int N) 
// Outputs K sorted random integers out of 0..N, taken according to 
// [Vitter87], method A. 
    { 
    int top=N-K, S, curr=0, currsample=-1; 
    double Nreal=N, quot=1., V; 

    while (K>=2) 
     { 
     V=uni(); 
     S=0; 
     quot=top/Nreal; 
     while (quot > V) 
      { 
      S++; top--; Nreal--; 
      quot *= top/Nreal; 
      } 
     currsample+=1+S; 
     cout << curr << " : " << currsample << "\n"; 
     Nreal--; K--;curr++; 
     } 
    // special case K=1 to avoid overflow 
    S=floor(round(Nreal)*uni()); 
    currsample+=1+S; 
    cout << curr << " : " << currsample << "\n"; 
    } 

void SequentialSamplesMethodD(int K, int N) 
// Outputs K sorted random integers out of 0..N, taken according to 
// [Vitter87], method D. 
    { 
    const int negalphainv=-13; //between -20 and -7 according to [Vitter87] 
    //optimized for an implementation in 1987 !!! 
    int curr=0, currsample=0; 
    int threshold=-negalphainv*K; 
    double Kreal=K, Kinv=1./Kreal, Nreal=N; 
    double Vprime=exp(log(uni())*Kinv); 
    int qu1=N+1-K; double qu1real=qu1; 
    double Kmin1inv, X, U, negSreal, y1, y2, top, bottom; 
    int S, limit; 
    while ((K>1)&&(threshold<N)) 
     { 
     Kmin1inv=1./(Kreal-1.); 
     while(1) 
      {//Step D2: generate X and U 
      while(1) 
       { 
       X=Nreal*(1-Vprime); 
       S=floor(X); 
       if (S<qu1) {break;} 
       Vprime=exp(log(uni())*Kinv); 
       } 
      U=uni(); 
      negSreal=-S; 
      //step D3: Accept ? 
      y1=exp(log(U*Nreal/qu1real)*Kmin1inv); 
      Vprime=y1*(1. - X/Nreal)*(qu1real/(negSreal+qu1real)); 
      if (Vprime <=1.) {break;} //Accept ! Test [Vitter87](2.8) is true 
      //step D4 Accept ? 
      y2=0; top=Nreal-1.; 
      if (K-1 > S) 
       {bottom=Nreal-Kreal; limit=N-S;} 
      else {bottom=Nreal+negSreal-1.; limit=qu1;} 
      for(int t=N-1;t>=limit;t--) 
       {y2*=top/bottom;top--; bottom--;} 
      if (Nreal/(Nreal-X)>=y1*exp(log(y2)*Kmin1inv)) 
       {//Accept ! 
       Vprime=exp(log(uni())*Kmin1inv); 
       break; 
       } 
      Vprime=exp(log(uni())*Kmin1inv); 
      } 
     // Step D5: Select the (S+1)th record 
     currsample+=1+S; 
     cout << curr << " : " << currsample << "\n"; 
     curr++; 
     N-=S+1; Nreal+=negSreal-1.; 
     K-=1; Kreal-=1; Kinv=Kmin1inv; 
     qu1-=S; qu1real+=negSreal; 
     threshold+=negalphainv; 
     } 
    if (K>1) {SequentialSamplesMethodA(K, N);} 
    else { 
     S=floor(N*Vprime); 
     currsample+=1+S; 
     cout << curr << " : " << currsample << "\n"; 
     } 
    } 


int main(void) 
    { 
    int Ntest=10000000, Ktest=Ntest/100; 
    SequentialSamplesMethodD(Ktest,Ntest); 
    return 0; 
    } 

$ time ./sampling|tail 

अपने लैपटॉप

99990 : 9998882 
99991 : 9998885 
99992 : 9999021 
99993 : 9999058 
99994 : 9999339 
99995 : 9999359 
99996 : 9999411 
99997 : 9999427 
99998 : 9999584 
99999 : 9999745 

real 0m0.075s 
user 0m0.060s 
sys 0m0.000s 
+0

http://stackoverflow.com/a/2394292/648265 के अनुसार, यह संयोजन उत्पन्न करता है। क्रमपरिवर्तन नहीं। –

+0

पूछा गया था कि "के गैर दोहराने वाले पूर्णांक की एक सूची" क्रमपरिवर्तन नहीं है। और मैंने अपने जवाब में निर्दिष्ट किया है "यदि आप आदेश से रूचि नहीं रखते हैं" –

1

चरण 1 पर निम्नलिखित ouptut देता है: पूर्णांकों की अपनी सूची उत्पन्न करें।
चरण 2: Knuth Shuffle प्रदर्शन करें।

ध्यान दें कि आपको पूरी सूची को घुमाने की आवश्यकता नहीं है, क्योंकि Knuth Shuffle एल्गोरिदम आपको केवल n shuffles लागू करने की अनुमति देता है, जहां n वापस आने वाले तत्वों की संख्या है। सूची उत्पन्न करने से सूची के आकार के लिए आनुपातिक समय लगेगा, लेकिन आप किसी भी भविष्य की शफलिंग आवश्यकताओं के लिए अपनी मौजूदा सूची का पुन: उपयोग कर सकते हैं (आकार मानते हुए मानते हैं) शफलिंग एल्गोरिदम को पुनरारंभ करने से पहले आंशिक रूप से शफल सूची को पूर्ववत करने की आवश्यकता नहीं है।

Knuth Shuffle के लिए मूल एल्गोरिदम यह है कि आप पूर्णांक की एक सूची से शुरू करते हैं। फिर, आप सूची में किसी भी संख्या के साथ पहला पूर्णांक स्वैप करें और वर्तमान (नया) पहला पूर्णांक वापस कर दें। फिर, आप सूची में किसी भी संख्या के साथ दूसरे पूर्णांक को स्वैप करें (पहले को छोड़कर) और वर्तमान (नया) दूसरा पूर्णांक लौटाएं। फिर ... आदि ...

यह एक बेहद सरल एल्गोरिदम है, लेकिन सावधान रहें कि आप स्वैप करने के दौरान सूची में वर्तमान आइटम को शामिल करते हैं या आप एल्गोरिदम तोड़ देंगे।

0

यह रूबी कोड Reservoir Sampling, Algorithm R विधि दिखाता है। प्रत्येक चरण में, मैं [0,N=10) सीमा से n=5 अद्वितीय यादृच्छिक पूर्णांकों का चयन करें:

t=0 
m=0 
N=10 
n=5 
s=0 
distrib=Array.new(N,0) 
for i in 1..500000 do 
t=0 
m=0 
s=0 
while m<n do 

    u=rand() 
    if (N-t)*u>=n-m then 
    t=t+1 
    else 
    distrib[s]+=1 
    m=m+1 
    t=t+1 
    end #if 
    s=s+1 
end #while 
if (i % 100000)==0 then puts i.to_s + ". cycle..." end 
end #for 
puts "--------------" 
puts distrib 

उत्पादन:

100000. cycle... 
200000. cycle... 
300000. cycle... 
400000. cycle... 
500000. cycle... 
-------------- 
250272 
249924 
249628 
249894 
250193 
250202 
249647 
249606 
250600 
250034 

0-9 के बीच सभी पूर्णांक लगभग एक ही संभावना के साथ चुने गए हैं।

यह अनिवार्य रूप से Knuth's algorithm मनमाने ढंग से अनुक्रमों पर लागू होता है (वास्तव में, उस उत्तर में इसका एक LISP संस्करण है)। एल्गोरिदम ओ (एन) समय में है और ओ (1) मेमोरी में हो सकता है यदि क्रम में @MichaelCramer's answer में दिखाया गया है।

+0

आपको विधि की गुणवत्ता को वास्तव में दिखाने के लिए अलग-अलग संख्याओं के बजाय प्रत्येक पूर्ण क्रमपरिवर्तन की संभावना को मापना चाहिए - अन्यथा, आप केवल संख्या सेट चयन की यादृच्छिकता दिखाते हैं, उनके आदेश की नहीं। –

संबंधित मुद्दे