ओ (1) में अद्वितीय (गैर-दोहराव) यादृच्छिक संख्या?


179

मैं 0 और 1000 के बीच अद्वितीय यादृच्छिक संख्याएँ उत्पन्न करना चाहता हूँ जो कभी भी दोहराई नहीं जाती हैं (अर्थात 6 दो बार दिखाई नहीं देती हैं), लेकिन यह ऐसा करने के लिए पिछले मानों की O (N) खोज जैसी किसी चीज़ का सहारा नहीं लेती है। क्या यह संभव है?


4
क्या यह वही सवाल नहीं है जैसा कि stackoverflow.com/questions/158716/…
jk।

2
0 और 1000 के बीच 0 है?
पीट किरकम

4
यदि आप निरंतर समय (जैसे O(n)समय या स्मृति) पर कुछ भी रोक रहे हैं , तो नीचे दिए गए कई उत्तर गलत हैं, जिनमें स्वीकृत उत्तर भी शामिल है।
jww

आप कार्ड का एक पैकेट कैसे फेरबदल करेंगे?
कर्नल पैनिक

9
चेतावनी! नीचे दिए गए जवाबों में से कई सही मायने में यादृच्छिक क्रम उत्पन्न नहीं करते हैं, O (n) या अन्यथा दोषपूर्ण हैं! इससे पहले कि आप उनमें से किसी का उपयोग करें या अपने स्वयं के मनगढ़ंत करने की कोशिश करें, कोडिंगहोरर.com/blog/archives/001015.html एक आवश्यक रीड है।
ivan_pozdeev

जवाबों:


247

0-1000 मानों के साथ 1001 पूर्णांक की एक सरणी की शुरुआत करें और सरणी के वर्तमान अधिकतम सूचकांक (1000 से शुरू) के लिए एक चर, अधिकतम सेट करें। 0 और अधिकतम के बीच एक यादृच्छिक संख्या, आर उठाओ, स्थिति आर पर संख्या के साथ स्थिति अधिकतम पर स्वैप करें और अब स्थिति अधिकतम पर संख्या वापस करें। कमी अधिकतम 1 और जारी है। जब अधिकतम 0 होता है, तो सरणी के आकार में अधिकतम वापस सेट करें - 1 और सरणी को फिर से संगठित करने की आवश्यकता के बिना फिर से शुरू करें।

अद्यतन: हालांकि मैं अपने आप ही इस पद्धति के साथ आया था जब मैंने प्रश्न का उत्तर दिया था, कुछ शोध के बाद मुझे पता चला कि यह फिशर-येट्स का एक संशोधित संस्करण है जिसे डर्स्टनफील्ड-फिशर-येट्स या नूथ-फिशर-येट्स के रूप में जाना जाता है। चूंकि वर्णन का पालन करना थोड़ा मुश्किल हो सकता है, मैंने नीचे एक उदाहरण दिया है (1001 के बजाय 11 तत्वों का उपयोग करके):

सरणी से शुरू होने वाले 11 तत्वों के साथ ऐरे शुरू होता है [n] = n, अधिकतम 10 पर शुरू होता है:

+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|
+--+--+--+--+--+--+--+--+--+--+--+
                                ^
                               max    

प्रत्येक पुनरावृत्ति पर, 0 और अधिकतम के बीच एक यादृच्छिक संख्या r का चयन किया जाता है, सरणी [r] और सरणी [max] की अदला-बदली की जाती है, नया सरणी [max] वापस किया जाता है, और अधिकतम को घटाया जाता है:

max = 10, r = 3
           +--------------------+
           v                    v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 7| 8| 9| 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 9, r = 7
                       +-----+
                       v     v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 9| 8| 7: 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 8, r = 1
     +--------------------+
     v                    v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 5| 6| 9| 1: 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 7, r = 5
                 +-----+
                 v     v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 9| 6| 5: 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

...

11 पुनरावृत्तियों के बाद, सरणी में सभी संख्याएं चुनी गई हैं, अधिकतम == 0, और सरणी तत्वों को फेरबदल किया गया है:

+--+--+--+--+--+--+--+--+--+--+--+
| 4|10| 8| 6| 2| 0| 9| 5| 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

इस बिंदु पर, अधिकतम 10 पर रीसेट किया जा सकता है और प्रक्रिया जारी रह सकती है।


6
पुथल पर जेफ के पद से पता चलता है यह अच्छा यादृच्छिक संख्या वापस नहीं होगा .. codinghorror.com/blog/archives/001015.html
समर्थक

14
@ पैटर राइज़: मुझे नहीं लगता; यह मुझे फिशर येट्स एल्गोरिदम की तरह दिखता है, जिसे जेफ के पोस्ट (अच्छे आदमी के रूप में) में भी उद्धृत किया गया है।
ब्रेंटलॉन्गबरो

3
@robert: मैं केवल यह इंगित करना चाहता था कि यह उत्पादन नहीं करता है, जैसा कि सवाल के नाम पर है, "O (1) में अद्वितीय यादृच्छिक संख्या"।
चार्ल्स

3
@ माइकेरा: सहमत, हालांकि तकनीकी रूप से यदि आप निश्चित आकार के पूर्णांक का उपयोग कर रहे हैं तो पूरी सूची O (1) (बड़े स्थिरांक, 2 ^ 32) के साथ उत्पन्न की जा सकती है। व्यावहारिक उद्देश्यों के लिए, "यादृच्छिक" की परिभाषा महत्वपूर्ण है - यदि आप वास्तव में अपने सिस्टम के एन्ट्रापी पूल का उपयोग करना चाहते हैं, तो सीमा स्वयं गणना के बजाय यादृच्छिक बिट्स की गणना है, और उस स्थिति में एन लॉग एन प्रासंगिक है फिर। लेकिन इस मामले में कि आप / dev / यादृच्छिक के बजाय (/ के बराबर) / dev / urandom का उपयोग करेंगे, आप 'व्यावहारिक रूप से' O (n) पर लौट आएंगे।
चार्ल्स

4
मैं थोड़ा उलझन में हूँ, क्या इस तथ्य को प्रदर्शित नहीं करना है कि आपको Nप्रत्येक बार इसका वांछित परिणाम प्राप्त करने के लिए पुनरावृत्तियों (इस उदाहरण में 11) करना होगा O(n)? जैसा कि आपको एक ही प्रारंभिक अवस्था से संयोजन Nप्राप्त करने के लिए पुनरावृत्तियों को करने की आवश्यकता है N!, अन्यथा आपका आउटपुट केवल एन राज्यों में से एक होगा।
Seph

71

तुम यह केर सकते हो:

  1. एक सूची बनाएं, 0..1000।
  2. सूची में फेरबदल करें। (यह करने के लिए एक अच्छा तरीका के लिए फिशर-येट्स फेरबदल देखें ।)
  3. क्रमवार सूची से क्रमांक वापस करें।

इसलिए इसे हर बार पुराने मूल्यों की खोज की आवश्यकता नहीं होती है, लेकिन प्रारंभिक फेरबदल के लिए इसे अभी भी O (N) की आवश्यकता होती है। लेकिन जैसा कि निल्स ने टिप्पणियों में बताया है, यह परिशोधन हे (1) है।


5
@ जस्ट सम गाइ एन = 1000, तो आप कह रहे हैं कि यह ओ (एन / एन) है जो ओ (1) है
गुवाँटे

1
यदि कटा हुआ सरणी में प्रत्येक सम्मिलित एक ऑपरेशन है, तो 1 मूल्य डालने के बाद, आप 1 यादृच्छिक मान प्राप्त कर सकते हैं। 2 के लिए 2 मान, और इतने पर, n मान के लिए एन। यह सूची उत्पन्न करने के लिए n संचालन लेता है, इसलिए संपूर्ण एल्गोरिथ्म O (n) है। यदि आपको 1,000,000 यादृच्छिक मूल्यों की आवश्यकता है, तो यह 1,000,000 ऑप्स लेगा
किबी

3
इसके बारे में इस तरह से सोचें, अगर यह लगातार समय होता, तो यह 10 यादृच्छिक संख्याओं के लिए उतना ही समय लेता जितना कि यह 10 बिलियन के लिए होगा। लेकिन O (n) में फेरबदल के कारण, हम जानते हैं कि यह सच नहीं है।
कबि

1
यह वास्तव में amortized समय O (log n) लेता है, क्योंकि आपको n lg n यादृच्छिक बिट्स उत्पन्न करने की आवश्यकता है।
चार्ल्स

2
और अब, मेरे पास इसे करने का सभी औचित्य है! meta.stackoverflow.com/q/252503/13
क्रिस

60

एक अधिकतम रैखिक प्रतिक्रिया शिफ्ट रजिस्टर का उपयोग करें ।

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


12
"यह यादृच्छिक नहीं है, लेकिन यह ज्यादातर लोगों को बेवकूफ बनाता है"। यह सभी छद्म यादृच्छिक संख्या जनरेटर और इस प्रश्न के सभी संभव जवाबों पर लागू होता है। लेकिन ज्यादातर लोग इसके बारे में नहीं सोचेंगे। इसलिए इस नोट को छोड़ने से शायद अधिक वृद्धि होगी ...
f3lix

3
@ बोबोबोबो: ओ (1) मेमोरी क्यों है।
ऐश

3
Nit: यह O (लॉग एन) मेमोरी है।
पॉल हैंकिन

2
उस पद्धति का उपयोग करते हुए, आप 0 और 800000 के बीच संख्याओं को कैसे उत्पन्न करते हैं? कुछ लोग LFSR का उपयोग कर सकते हैं, जिसकी अवधि 1048575 (2 ^ 20 - 1) है और यदि नंबर सीमा से बाहर है, लेकिन यह कुशल नहीं होगा।
टाइगरो

1
एलएफएसआर के रूप में, यह समान रूप से वितरित अनुक्रमों का उत्पादन नहीं करता है : उत्पन्न होने वाला संपूर्ण अनुक्रम पहले तत्व द्वारा परिभाषित किया गया है।
ivan_pozdeev

21

आप एक रैखिक बधाई जेनरेटर का उपयोग कर सकते हैं । जहाँ m(मापांक) 1000 से निकटतम सबसे बड़ा होगा। जब आप एक सीमा से बाहर संख्या प्राप्त करते हैं, तो बस अगला प्राप्त करें। सभी तत्वों के होने के बाद अनुक्रम केवल दोहराएगा, और आपको तालिका का उपयोग करने की आवश्यकता नहीं है। हालांकि इस जनरेटर के नुकसान से अवगत रहें (यादृच्छिकता की कमी सहित)।


1
१००० के बाद १०० ९ पहला प्रधान है।
टेपेमेम

एक LCG में लगातार संख्याओं के बीच उच्च सहसंबंध होता है, इस प्रकार संयोजन बड़े पैमाने पर यादृच्छिक नहीं होगा (उदाहरण के kअलावा क्रम से अलग संख्या कभी भी एक साथ नहीं हो सकती है)।
ivan_pozdeev 21

मीटर तत्वों की संख्या 1001 (शून्य के लिए 1000 + 1) होनी चाहिए और आप अगला = (1002 * वर्तमान + 757) मॉड 1001 का उपयोग कर सकते हैं;
मैक्स अब्रामोविच

21

आप किसी काउंटर को एन्क्रिप्ट करने के लिए फॉर्मेट-प्रिजर्विंग एन्क्रिप्शन का उपयोग कर सकते हैं । आपका काउंटर सिर्फ 0 से ऊपर की ओर जाता है, और एन्क्रिप्शन आपकी पसंद की एक कुंजी का उपयोग करता है, जो कि आप जिस भी मूलांक और चौड़ाई को चाहते हैं, वह प्रतीत होता है। उदाहरण के लिए इस प्रश्न में: मूलांक 10, चौड़ाई 3।

ब्लॉक सिफर में सामान्य रूप से एक निश्चित ब्लॉक आकार होता है जैसे 64 या 128 बिट्स। लेकिन प्रारूप-संरक्षण एन्क्रिप्शन आपको AES की तरह एक मानक सिफर लेने की अनुमति देता है और जो भी मूलांक और चौड़ाई आप चाहते हैं उसकी छोटी-सी चौड़ाई का सिफर बनाते हैं, एक एल्गोरिथ्म के साथ जो अभी भी क्रिप्टोग्राफिक रूप से मजबूत है।

यह कभी नहीं टकराने की गारंटी है (क्योंकि क्रिप्टोग्राफिक एल्गोरिदम 1: 1 मैपिंग बनाते हैं)। यह प्रतिवर्ती (2-वे मैपिंग) भी है, इसलिए आप परिणामी संख्या ले सकते हैं और आपके द्वारा शुरू किए गए काउंटर मान पर वापस जा सकते हैं।

इस तकनीक को एक फेरबदल सरणी आदि को स्टोर करने के लिए मेमोरी की आवश्यकता नहीं होती है, जो सीमित मेमोरी वाले सिस्टम पर एक फायदा हो सकता है।

एईएस-एफएफएक्स इसे प्राप्त करने के लिए एक प्रस्तावित मानक विधि है। मैंने कुछ मूल पायथन कोड के साथ प्रयोग किया है जो एईएस-एफएफएक्स विचार पर आधारित है, हालांकि पूरी तरह से अनुरूप नहीं है - यहां पायथन कोड देखें । यह उदाहरण के लिए एक काउंटर को यादृच्छिक-दिखने वाले 7-अंकीय दशमलव संख्या, या 16-बिट संख्या में एन्क्रिप्ट कर सकता है। यहां बताया गया है कि मूलांक 10, चौड़ाई 3 (उदाहरण 0 और 999 के बीच की संख्या देने के लिए) का एक उदाहरण है:

000   733
001   374
002   882
003   684
004   593
005   578
006   233
007   811
008   072
009   337
010   119
011   103
012   797
013   257
014   932
015   433
...   ...

अलग-अलग गैर-दोहराए जाने वाले छद्म यादृच्छिक क्रम प्राप्त करने के लिए, एन्क्रिप्शन कुंजी को बदलें। प्रत्येक एन्क्रिप्शन कुंजी एक अलग गैर-दोहराए जाने वाले छद्म यादृच्छिक क्रम का उत्पादन करती है।


यह अनिवार्य रूप से एक साधारण मानचित्रण है, इस प्रकार एलसीजी और एलएफएसआर से अलग नहीं है, सभी प्रासंगिक किंक के साथ (जैसे kअनुक्रम में अलग-अलग मूल्य एक साथ कभी भी नहीं हो सकते हैं)।
ivan_pozdeev 21

@ivan_pozdeev: मुझे आपकी टिप्पणी का अर्थ समझने में कठिनाई हो रही है। क्या आप बता सकते हैं कि इस मैपिंग में क्या गलत है, "सभी संबंधित किंक" क्या हैं, और क्या है k?
क्रेग मैकक्यून

यहां सभी "एन्क्रिप्शन" प्रभावी रूप से करता है, अनुक्रम 1,2,...,Nको उसी संख्या के अनुक्रम के साथ कुछ अन्य में बदल देता है, लेकिन फिर भी निरंतर, क्रम। इस क्रम से एक-एक करके संख्याएँ खींची जाती हैं। kउठाए गए मूल्यों की संख्या है (ओपी ने इसके लिए कोई पत्र निर्दिष्ट नहीं किया था इसलिए मुझे एक परिचय देना पड़ा)।
ivan_pozdeev

3
@ivan_pozdeev यह ऐसा नहीं है कि FPE को एक विशिष्ट स्थैतिक मानचित्रण को लागू करना चाहिए, या यह कि "लौटाए गए संयोजन को पहले नंबर से पूरी तरह परिभाषित किया गया है"। चूंकि कॉन्फ़िगरेशन पैरामीटर पहले नंबर के आकार (जो केवल एक हजार राज्य है) से बहुत बड़ा है, ऐसे कई अनुक्रम होने चाहिए जो एक ही प्रारंभिक मूल्य से शुरू होते हैं और फिर बाद के मूल्यों पर आगे बढ़ते हैं। कोई भी यथार्थवादी जनरेटर क्रमपरिवर्तन के पूरे संभावित स्थान को कवर करने में विफल रहा है; यह उस विफलता मोड को बढ़ाने के लायक नहीं है जब ओपी ने इसके लिए नहीं पूछा।
sh1

4
+1। जब सही ढंग से कार्यान्वित किया जाता है, तो एक समान रूप से यादृच्छिक रूप से चुने गए कुंजी के साथ एक सुरक्षित ब्लॉक सिफर का उपयोग करके, इस पद्धति का उपयोग करके उत्पन्न अनुक्रमों को एक सच्चे यादृच्छिक फेरबदल से कम्प्यूटेशनल रूप से अप्रभेद्य किया जाएगा। कहने का तात्पर्य यह है कि, इस पद्धति के आउटपुट को एक सच्चे यादृच्छिक फेरबदल से अलग करने का कोई तरीका नहीं है, जो सभी संभावित ब्लॉक सिफर कुंजी का परीक्षण करके और यदि उनमें से कोई भी समान आउटपुट उत्पन्न करता है, तो उसे देखने का कोई तरीका नहीं है। 128-बिट कीस्पेस के साथ एक सिफर के लिए, यह संभवतः कंप्यूटिंग शक्ति से परे है जो वर्तमान में मानव जाति के लिए उपलब्ध है; 256-बिट कुंजी के साथ, यह शायद हमेशा के लिए रहेगा।
इल्मरी करोनें

7

कम संख्याओं जैसे 0 ... 1000 के लिए, एक ऐसी सूची बनाना जिसमें सभी संख्याएँ हों और इसे फेरबदल करना सीधे आगे हो। लेकिन अगर संख्याओं के सेट से ड्रा करना बहुत बड़ा है, तो एक और सुरुचिपूर्ण तरीका है: आप एक कुंजी और एक क्रिप्टोग्राफ़िक हैश फ़ंक्शन का उपयोग करके एक छद्म आयामी क्रमांकन का निर्माण कर सकते हैं। निम्नलिखित C ++ - ish उदाहरण छद्म कोड देखें:

unsigned randperm(string key, unsigned bits, unsigned index) {
  unsigned half1 =  bits    / 2;
  unsigned half2 = (bits+1) / 2;
  unsigned mask1 = (1 << half1) - 1;
  unsigned mask2 = (1 << half2) - 1;
  for (int round=0; round<5; ++round) {
    unsigned temp = (index >> half1);
    temp = (temp << 4) + round;
    index ^= hash( key + "/" + int2str(temp) ) & mask1;
    index = ((index & mask2) << half1) | ((index >> half2) & mask1);
  }
  return index;
}

यहाँ, hashबस कुछ मनमाने ढंग से छद्म यादृच्छिक फ़ंक्शन है जो एक चरित्र स्ट्रिंग को संभवतः बहुत अधिक अहस्ताक्षरित पूर्णांक में मैप करता है। फ़ंक्शन randperm0 ... pow (2, बिट्स) -1 के भीतर सभी नंबरों का एक क्रमांकन है, जो एक निश्चित कुंजी है। यह निर्माण से निम्नानुसार है क्योंकि चर indexको बदलने वाला प्रत्येक चरण प्रतिवर्ती है। यह एक फिस्टल सिफर से प्रेरित है ।


के रूप में ही stackoverflow.com/a/16097246/648265 , दृश्यों सिर्फ एक ही के लिए अनियमितता विफल रहता है।
ivan_pozdeev

1
@ivan_pozdeev: सिद्धांत रूप में, अनंत कंप्यूटिंग शक्ति को मानते हुए, हाँ। हालांकि, यह मानते हुए कि hash(), जैसा कि ऊपर दिए गए कोड में उपयोग किया गया है, एक सुरक्षित छद्म आयामी कार्य है, यह निर्माण निश्चित रूप से होगा (लुबी एंड रैकॉफ, 1988) एक छद्म-आयामी क्रमपरिवर्तन उत्पन्न करता है , जिसे एक व्यापक यादृच्छिक प्रयास से अलग नहीं किया जा सकता है, जो एक थकावट की तुलना में काफी कम प्रयास का उपयोग करता है। संपूर्ण कुंजी स्थान की खोज, जो कि प्रमुख लंबाई में घातांक है। यहां तक ​​कि काफी आकार की कुंजियों के लिए (कहते हैं, 128 बिट्स), यह पृथ्वी पर उपलब्ध कुल कंप्यूटिंग शक्ति से परे है।
इल्मरी करोनें

(BTW, बस इस तर्क को थोड़ा और अधिक कठोर बनाने के लिए, मैं HMAC केhash( key + "/" + int2str(temp) ) साथ ऊपर दिए गए तदर्थ निर्माण को प्रतिस्थापित करना पसंद करूंगा , जिसकी बदले में सुरक्षा को अंतर्निहित हैश संपीड़न फ़ंक्शन के लिए काफी कम किया जा सकता है। इसके अलावा, HMAC का उपयोग कर सकते हैं। किसी व्यक्ति द्वारा गलत तरीके से असुरक्षित गैर-क्रिप्टो हैश फ़ंक्शन के साथ इस निर्माण का उपयोग करने की कोशिश करने की संभावना कम है।)
इल्मरी करोनन सेप

6

आप यहाँ वर्णित मेरे Xincrol एल्गोरिथ्म का उपयोग कर सकते हैं:

http://openpatent.blogspot.co.il/2013/04/xincrol-unique-and-random-number.html

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

नवीनतम संस्करण भी संख्याओं की सीमा निर्धारित करने की अनुमति देता है, उदाहरण के लिए, यदि मैं 0-1073741821 की सीमा में अद्वितीय यादृच्छिक संख्याएँ चाहता हूँ।

मैंने व्यावहारिक रूप से इसके लिए उपयोग किया है

  • एमपी 3 प्लेयर जो हर गाने को बेतरतीब ढंग से बजाता है, लेकिन केवल एक बार प्रति एल्बम / डायरेक्टरी
  • पिक्सेल वार वीडियो फ्रेम विघटित प्रभाव (तेज और चिकनी)
  • हस्ताक्षर और मार्कर (स्टेग्नोग्राफ़ी) के लिए छवि पर एक गुप्त "शोर" कोहरा बनाना
  • डेटाबेस के माध्यम से भारी मात्रा में जावा ऑब्जेक्ट्स के क्रमांकन के लिए डेटा ऑब्जेक्ट आईडी
  • ट्रिपल मेजरिटी मेमोरी बिट्स सुरक्षा
  • पता + मान एन्क्रिप्शन (प्रत्येक बाइट न केवल एन्क्रिप्ट किया गया है, बल्कि बफर में एक नए एन्क्रिप्टेड स्थान पर भी स्थानांतरित किया गया है)। यह वास्तव में मुझ पर क्रिप्टोकरंसी फेलो बना दिया है :-)
  • प्लेन टेक्स्ट टू प्लेन लाइक क्रिप्ट टेक्स्ट एन्क्रिप्शन फॉर एसएमएस, ईमेल्स आदि।
  • मेरा टेक्सास होल्डम पोकर कैलकुलेटर (THC)
  • सिमुलेशन के लिए मेरे कई खेल, "फेरबदल", रैंकिंग
  • अधिक

यह खुला है, मुफ्त है। कोशिश करो...


क्या यह विधि एक दशमलव मान के लिए काम कर सकती है, उदाहरण के लिए 3-अंकों वाले दशमलव काउंटर को हमेशा 3 अंकों के दशमलव परिणाम पर रखना?
क्रेग मैकक्वीन

Xorshift एल्गोरिथ्म के एक उदाहरण के रूप में , यह एक LFSR है, सभी संबंधित किंक के साथ (जैसे kअनुक्रम में अलग-अलग मान एक साथ कभी नहीं हो सकते हैं)।
ivan_pozdeev 21

5

आपको इसे हल करने के लिए किसी सरणी की भी आवश्यकता नहीं है।

आपको एक बिटमास्क और एक काउंटर की आवश्यकता है।

काउंटर को शून्य पर शुरू करें और इसे लगातार कॉल पर बढ़ाएँ। एक psuedorandom संख्या उत्पन्न करने के लिए बिटमस्क (स्टार्टअप पर यादृच्छिक रूप से चयनित, या निश्चित) के साथ काउंटर XOR। यदि आपके पास संख्याएँ नहीं हैं जो 1000 से अधिक हैं, तो 9 बिट्स की तुलना में व्यापक बिटमैप का उपयोग न करें। (दूसरे शब्दों में, बिटमस्क एक पूर्णांक है जो 511 से ऊपर नहीं है।)

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


2
यह एक LFSR से कम लोगों को बेवकूफ बना देगा।
starblue

512 के भीतर "बिटमास्क" ... 1023 भी ठीक है। थोड़ी और नकली बेतरतीबी के लिए मेरा जवाब देखें। :-)
बिक्री

अनिवार्य रूप से करने के लिए बराबर stackoverflow.com/a/16097246/648265 , भी दृश्यों के लिए अनियमितता विफल रहता है।
ivan_pozdeev 22

4

मुझे लगता है कि रैखिक बधाई जनरेटर सबसे सरल समाधान होगा।

यहां छवि विवरण दर्ज करें

और , सी और एम मूल्यों पर केवल 3 प्रतिबंध हैं

  1. मी और सी अपेक्षाकृत प्रमुख हैं,
  2. a-1 m के सभी प्रमुख कारकों द्वारा विभाज्य है
  3. एक-1 से विभाज्य है 4 अगर मीटर से विभाज्य है 4

पी एस विधि पहले ही उल्लेख किया गया था, लेकिन पोस्ट में निरंतर मूल्यों के बारे में गलत धारणा है। नीचे दिए गए स्थिरांक आपके मामले के लिए ठीक काम करना चाहिए

आपके मामले में आप उपयोग कर सकते हैं a = 1002, c = 757,m = 1001

X = (1002 * X + 757) mod 1001

3

यहां कुछ कोड मैंने टाइप किए हैं जो पहले समाधान के तर्क का उपयोग करते हैं। मुझे पता है कि यह "भाषा अज्ञेय" है, लेकिन बस इसे C # में एक उदाहरण के रूप में प्रस्तुत करना चाहता था, अगर कोई भी त्वरित व्यावहारिक समाधान की तलाश में है।

// Initialize variables
Random RandomClass = new Random();
int RandArrayNum;
int MaxNumber = 10;
int LastNumInArray;
int PickedNumInArray;
int[] OrderedArray = new int[MaxNumber];      // Ordered Array - set
int[] ShuffledArray = new int[MaxNumber];     // Shuffled Array - not set

// Populate the Ordered Array
for (int i = 0; i < MaxNumber; i++)                  
{
    OrderedArray[i] = i;
    listBox1.Items.Add(OrderedArray[i]);
}

// Execute the Shuffle                
for (int i = MaxNumber - 1; i > 0; i--)
{
    RandArrayNum = RandomClass.Next(i + 1);         // Save random #
    ShuffledArray[i] = OrderedArray[RandArrayNum];  // Populting the array in reverse
    LastNumInArray = OrderedArray[i];               // Save Last Number in Test array
    PickedNumInArray = OrderedArray[RandArrayNum];  // Save Picked Random #
    OrderedArray[i] = PickedNumInArray;             // The number is now moved to the back end
    OrderedArray[RandArrayNum] = LastNumInArray;    // The picked number is moved into position
}

for (int i = 0; i < MaxNumber; i++)                  
{
    listBox2.Items.Add(ShuffledArray[i]);
}

3

जब सीमा अधिक होती है और आप केवल कुछ रैंडम संख्याएँ उत्पन्न करना चाहते हैं, तो यह विधि परिणाम का मूल्यांकन करती है।

#!/usr/bin/perl

($top, $n) = @ARGV; # generate $n integer numbers in [0, $top)

$last = -1;
for $i (0 .. $n-1) {
    $range = $top - $n + $i - $last;
    $r = 1 - rand(1.0)**(1 / ($n - $i));
    $last += int($r * $range + 1);
    print "$last ($r)\n";
}

ध्यान दें कि संख्याएं आरोही क्रम में उत्पन्न होती हैं, लेकिन आप बाद में फेरबदल कर सकते हैं।


चूंकि यह क्रमपरिवर्तन के बजाय संयोजन उत्पन्न करता है, इसलिए यह stackoverflow.com/questions/2394246/… के
ivan_pozdeev

1
परीक्षण से पता चलता है कि इसमें निम्न संख्याओं के लिए एक पूर्वाग्रह है: 2M नमूनों के लिए मापा संभावनाएँ (top,n)=(100,10)हैं (0.01047705, 0.01044825, 0.01041225, ..., 0.0088324, 0.008723, 0.00863635):। मैंने पायथन में परीक्षण किया, इसलिए गणित में थोड़े अंतर यहां एक भूमिका निभा सकते हैं (मैंने यह सुनिश्चित किया कि गणना के लिए सभी ऑपरेशन rफ्लोटिंग-पॉइंट हैं)।
ivan_pozdeev

हां, इस विधि को सही ढंग से काम करने के लिए, ऊपरी सीमा को निकाले जाने वाले मूल्यों की संख्या से बहुत बड़ा होना चाहिए।
सलवा

यह "सही ढंग से" काम नहीं करेगा भले ही "ऊपरी सीमा [] मूल्यों की संख्या से बहुत बड़ी हो" । संभावनाएं अभी भी असमान होंगी, बस कुछ ही कम अंतर से।
ivan_pozdeev

2

आप 10 बिट के साथ एक अच्छा छद्म यादृच्छिक संख्या जनरेटर का उपयोग कर सकते हैं और 0 से 1000 को छोड़कर 1001 से 1023 तक फेंक सकते हैं।

से यहाँ हम एक 10 बिट PRNG के लिए डिजाइन मिल ..

  • 10 बिट, प्रतिक्रिया बहुपद x ^ 10 + x ^ 7 + 1 (अवधि 1023)

  • तेज कोड प्राप्त करने के लिए एक गैल्वेन LFSR का उपयोग करें


@Phob नहीं, ऐसा नहीं होगा, क्योंकि रैखिक प्रतिक्रिया शिफ्ट रजिस्टर के आधार पर 10 बिट PRNG आम तौर पर एक ऐसे निर्माण से बनाया जाता है जो पहले मान पर लौटने से पहले एक बार (एक को छोड़कर) सभी मानों को मान लेता है। दूसरे शब्दों में, यह केवल एक चक्र के दौरान एक बार ठीक 1001 उठाएगा।
नूओजी

1
@ इस प्रश्न का पूरा बिंदु एक बार प्रत्येक नंबर का चयन करना है। और फिर आप शिकायत करते हैं कि 1001 एक पंक्ति में दो बार नहीं होगा? एक इष्टतम प्रसार वाला एक LFSR एक छद्म यादृच्छिक फैशन में अपने स्थान पर सभी नंबरों को पीछे छोड़ देगा, फिर चक्र को पुनरारंभ करें। दूसरे शब्दों में, यह एक सामान्य यादृच्छिक फ़ंक्शन के रूप में उपयोग नहीं किया जाता है। जब एक यादृच्छिक के रूप में उपयोग किया जाता है, तो हम आम तौर पर केवल बिट्स के सबसेट का उपयोग करते हैं। इसके बारे में थोड़ा पढ़ें और यह जल्द ही समझ में आएगा।
नुओजी

1
एकमात्र समस्या यह है कि किसी दिए गए LFSR में केवल एक ही अनुक्रम होता है, इस प्रकार चुने हुए संख्याओं के बीच मजबूत सहसंबंध होता है - विशेष रूप से, हर संभव संयोजन उत्पन्न नहीं करता है।
ivan_pozdeev

2
public static int[] randN(int n, int min, int max)
{
    if (max <= min)
        throw new ArgumentException("Max need to be greater than Min");
    if (max - min < n)
        throw new ArgumentException("Range needs to be longer than N");

    var r = new Random();

    HashSet<int> set = new HashSet<int>();

    while (set.Count < n)
    {
        var i = r.Next(max - min) + min;
        if (!set.Contains(i))
            set.Add(i);
    }

    return set.ToArray();
}

आवश्यकता के अनुसार, नॉन रिपीटिंग रैंडम संख्या O (n) जटिलता की होगी।
नोट: रैंडम थ्रेड सुरक्षा के साथ स्थिर होना चाहिए।


O (n ^ 2), क्योंकि रिट्रीज़ की संख्या औसतन अब तक चयनित तत्वों की संख्या के अनुपात में है।
ivan_pozdeev

इसके बारे में सोचें, यदि आप मिनट = 0 अधिकतम = 10000000 और एन = 5 का चयन करते हैं, तो रिटायर ~ ~ 0 कोई फर्क नहीं पड़ता कि कितने चुने गए। लेकिन हां आपके पास एक बिंदु है कि अगर अधिकतम-मिनट छोटा है, तो ओ (एन) टूट जाता है।
इरेज़ रॉबिन्सन सेप

यदि एन << (अधिकतम-मिनट) तो यह अभी भी आनुपातिक है, यह सिर्फ गुणांक बहुत छोटा है। और गुणांक एक स्पर्शोन्मुख अनुमान के लिए कोई फर्क नहीं पड़ता।
ivan_pozdeev 22

यह O (n) नहीं है। हर बार सेट में यह मान होता है और अतिरिक्त लूप होता है।
पापाराजो

2

मान लीजिए कि आप O(n)बार-बार फेरबदल सूचियों पर जाना चाहते हैं, बिना देरी किए हर बार जब आप इसे फिर से बदलना शुरू करते हैं, उस स्थिति में हम यह कर सकते हैं:

  1. 0 से 1000 तक 2 सूचियाँ A और B बनाएँ, 2nस्थान लेता है।

  2. फिशर सूची ए फिशर-येट्स का उपयोग करते हुए, nसमय लगता है।

  3. जब एक संख्या खींचते हैं, तो दूसरी सूची में 1-स्टेप फिशर-येट्स फेरबदल करें।

  4. जब कर्सर सूची के अंत में है, तो दूसरी सूची पर जाएं।

preprocess

cursor = 0

selector = A
other    = B

shuffle(A)

खींचना

temp = selector[cursor]

swap(other[cursor], other[random])

if cursor == N
then swap(selector, other); cursor = 0
else cursor = cursor + 1

return temp

यह आवश्यक नहीं है कि 2 सूचियों को रखा जाए - या किसी सूची को खत्म करने से पहले समाप्त कर दिया जाए। फिशर-येट्स किसी भी प्रारंभिक अवस्था से समान रूप से यादृच्छिक परिणाम देता है। स्पष्टीकरण के लिए stackoverflow.com/a/158742/648265 देखें ।
ivan_pozdeev

@ivan_pozdeev हां, यह एक ही परिणाम है, लेकिन यहां मेरा विचार इसे ड्राइंग एक्शन का फेरबदल हिस्सा बनाकर O (1) को परिशोधित करना है।
खालिद.के।

आप समझ नहीं पाए। आपको फिर से फेरबदल करने से पहले सूची को रीसेट करने की आवश्यकता नहीं है । फेरबदल [1,3,4,5,2]करने के समान ही परिणाम देगा [1,2,3,4,5]
ivan_pozdeev 18

2

प्रश्न आप कुशलतापूर्वक 0 और एक ऊपरी बाध्य N के बीच K गैर-दोहराए जाने वाले पूर्णांकों की सूची कैसे बनाते हैं डुप्लिकेट के रूप में लिंक किया जाता है - और यदि आप ऐसा कुछ चाहते हैं जो O (1) प्रति उत्पन्न रैंडम संख्या है (बिना O (n) के स्टार्टअप लागत)) स्वीकृत उत्तर का एक सरल ट्वीक है।

एक खाली अनियंत्रित नक्शा (एक खाली ऑर्डर किया गया नक्शा ओ (लॉग के) प्रति तत्व) को पूर्णांक से पूर्णांक तक ले जाएगा - बजाय एक आरंभिक सरणी का उपयोग करने के। अधिकतम 1000 सेट करें यदि वह अधिकतम है,

  1. 0 और अधिकतम के बीच एक यादृच्छिक संख्या, r चुनें।
  2. सुनिश्चित करें कि मैप किए गए तत्व r और अधिकतम दोनों मौजूद हैं। यदि वे मौजूद नहीं हैं, तो उन्हें उनके सूचकांक के बराबर मूल्य के साथ बनाएं।
  3. स्वैप तत्व आर और अधिकतम
  4. वापसी तत्व अधिकतम और 1 से अधिकतम वृद्धि (यदि अधिकतम नकारात्मक हो जाता है)।
  5. चरण 1 पर वापस।

प्रारंभिक सरणी का उपयोग करने की तुलना में एकमात्र अंतर यह है कि तत्वों का आरंभीकरण स्थगित / छोड़ दिया जाता है - लेकिन यह समान PRNG से सटीक समान संख्या उत्पन्न करेगा।


1

एक और सकारात्मकता:

आप झंडे की एक सरणी का उपयोग कर सकते हैं। और जब यह पहले से ही चुना है, तो अगले एक को ले लो।

लेकिन, 1000 कॉल के बाद सावधान रहें, फ़ंक्शन कभी समाप्त नहीं होगा, इसलिए आपको एक सुरक्षा उपाय करना चाहिए।


यह ओ (k ^ 2) है, जो अब तक चुने गए मूल्यों की संख्या के औसत पर आनुपातिक अतिरिक्त चरणों की संख्या के साथ है।
ivan_pozdeev 22

1

यहाँ कुछ सैंपल COBOL कोड है जिनके साथ आप खेल सकते हैं।
मैं आपको RANDGEN.exe फ़ाइल भेज सकता हूं, ताकि आप यह देख सकें कि क्या आप इसे चाहते हैं।

   IDENTIFICATION DIVISION.
   PROGRAM-ID.  RANDGEN as "ConsoleApplication2.RANDGEN".
   AUTHOR.  Myron D Denson.
   DATE-COMPILED.
  * ************************************************************** 
  *  SUBROUTINE TO GENERATE RANDOM NUMBERS THAT ARE GREATER THAN
  *    ZERO AND LESS OR EQUAL TO THE RANDOM NUMBERS NEEDED WITH NO
  *    DUPLICATIONS.  (CALL "RANDGEN" USING RANDGEN-AREA.)
  *     
  *  CALLING PROGRAM MUST HAVE A COMPARABLE LINKAGE SECTION
  *    AND SET 3 VARIABLES PRIOR TO THE FIRST CALL IN RANDGEN-AREA     
  *
  *    FORMULA CYCLES THROUGH EVERY NUMBER OF 2X2 ONLY ONCE. 
  *    RANDOM-NUMBERS FROM 1 TO RANDOM-NUMBERS-NEEDED ARE CREATED 
  *    AND PASSED BACK TO YOU.
  *
  *  RULES TO USE RANDGEN:
  *
  *    RANDOM-NUMBERS-NEEDED > ZERO 
  *     
  *    COUNT-OF-ACCESSES MUST = ZERO FIRST TIME CALLED.
  *         
  *    RANDOM-NUMBER = ZERO, WILL BUILD A SEED FOR YOU
  *    WHEN COUNT-OF-ACCESSES IS ALSO = 0 
  *     
  *    RANDOM-NUMBER NOT = ZERO, WILL BE NEXT SEED FOR RANDGEN
  *    (RANDOM-NUMBER MUST BE <= RANDOM-NUMBERS-NEEDED)       
  *     
  *    YOU CAN PASS RANDGEN YOUR OWN RANDOM-NUMBER SEED
  *     THE FIRST TIME YOU USE RANDGEN.
  *     
  *    BY PLACING A NUMBER IN RANDOM-NUMBER FIELD
  *      THAT FOLLOWES THESE SIMPLE RULES:
  *        IF COUNT-OF-ACCESSES = ZERO AND 
  *        RANDOM-NUMBER > ZERO AND 
  *        RANDOM-NUMBER <= RANDOM-NUMBERS-NEEDED
  *       
  *    YOU CAN LET RANDGEN BUILD A SEED FOR YOU
  *     
  *      THAT FOLLOWES THESE SIMPLE RULES:
  *        IF COUNT-OF-ACCESSES = ZERO AND 
  *        RANDOM-NUMBER = ZERO AND 
  *        RANDOM-NUMBER-NEEDED > ZERO  
  *         
  *     TO INSURING A DIFFERENT PATTERN OF RANDOM NUMBERS
  *        A LOW-RANGE AND HIGH-RANGE IS USED TO BUILD
  *        RANDOM NUMBERS.
  *        COMPUTE LOW-RANGE =
  *             ((SECONDS * HOURS * MINUTES * MS) / 3).         
  *        A HIGH-RANGE = RANDOM-NUMBERS-NEEDED + LOW-RANGE
  *        AFTER RANDOM-NUMBER-BUILT IS CREATED 
  *        AND IS BETWEEN LOW AND HIGH RANGE
  *        RANDUM-NUMBER = RANDOM-NUMBER-BUILT - LOW-RANGE
  *               
  * **************************************************************         
   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.
   DATA DIVISION.
   FILE SECTION.
   WORKING-STORAGE SECTION.
   01  WORK-AREA.
       05  X2-POWER                     PIC 9      VALUE 2. 
       05  2X2                          PIC 9(12)  VALUE 2 COMP-3.
       05  RANDOM-NUMBER-BUILT          PIC 9(12)  COMP.
       05  FIRST-PART                   PIC 9(12)  COMP.
       05  WORKING-NUMBER               PIC 9(12)  COMP.
       05  LOW-RANGE                    PIC 9(12)  VALUE ZERO.
       05  HIGH-RANGE                   PIC 9(12)  VALUE ZERO.
       05  YOU-PROVIDE-SEED             PIC X      VALUE SPACE.
       05  RUN-AGAIN                    PIC X      VALUE SPACE.
       05  PAUSE-FOR-A-SECOND           PIC X      VALUE SPACE.   
   01  SEED-TIME.
       05  HOURS                        PIC 99.
       05  MINUTES                      PIC 99.
       05  SECONDS                      PIC 99.
       05  MS                           PIC 99. 
  *
  * LINKAGE SECTION.
  *  Not used during testing  
   01  RANDGEN-AREA.
       05  COUNT-OF-ACCESSES            PIC 9(12) VALUE ZERO.
       05  RANDOM-NUMBERS-NEEDED        PIC 9(12) VALUE ZERO.
       05  RANDOM-NUMBER                PIC 9(12) VALUE ZERO.
       05  RANDOM-MSG                   PIC X(60) VALUE SPACE.
  *    
  * PROCEDURE DIVISION USING RANDGEN-AREA.
  * Not used during testing 
  *  
   PROCEDURE DIVISION.
   100-RANDGEN-EDIT-HOUSEKEEPING.
       MOVE SPACE TO RANDOM-MSG. 
       IF RANDOM-NUMBERS-NEEDED = ZERO
         DISPLAY 'RANDOM-NUMBERS-NEEDED ' NO ADVANCING
         ACCEPT RANDOM-NUMBERS-NEEDED.
       IF RANDOM-NUMBERS-NEEDED NOT NUMERIC 
         MOVE 'RANDOM-NUMBERS-NEEDED NOT NUMERIC' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF RANDOM-NUMBERS-NEEDED = ZERO
         MOVE 'RANDOM-NUMBERS-NEEDED = ZERO' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF COUNT-OF-ACCESSES NOT NUMERIC
         MOVE 'COUNT-OF-ACCESSES NOT NUMERIC' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF COUNT-OF-ACCESSES GREATER THAN RANDOM-NUMBERS-NEEDED
         MOVE 'COUNT-OF-ACCESSES > THAT RANDOM-NUMBERS-NEEDED'
           TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF YOU-PROVIDE-SEED = SPACE AND RANDOM-NUMBER = ZERO
         DISPLAY 'DO YOU WANT TO PROVIDE SEED  Y OR N: '
           NO ADVANCING
           ACCEPT YOU-PROVIDE-SEED.  
       IF RANDOM-NUMBER = ZERO AND
          (YOU-PROVIDE-SEED = 'Y' OR 'y')
         DISPLAY 'ENTER SEED ' NO ADVANCING
         ACCEPT RANDOM-NUMBER. 
       IF RANDOM-NUMBER NOT NUMERIC
         MOVE 'RANDOM-NUMBER NOT NUMERIC' TO RANDOM-MSG
         GO TO 900-EXIT-RANDGEN.
   200-RANDGEN-DATA-HOUSEKEEPING.      
       MOVE FUNCTION CURRENT-DATE (9:8) TO SEED-TIME.
       IF COUNT-OF-ACCESSES = ZERO
         COMPUTE LOW-RANGE =
                ((SECONDS * HOURS * MINUTES * MS) / 3).
       COMPUTE RANDOM-NUMBER-BUILT = RANDOM-NUMBER + LOW-RANGE.  
       COMPUTE HIGH-RANGE = RANDOM-NUMBERS-NEEDED + LOW-RANGE.
       MOVE X2-POWER TO 2X2.             
   300-SET-2X2-DIVISOR.
       IF 2X2 < (HIGH-RANGE + 1) 
          COMPUTE 2X2 = 2X2 * X2-POWER
           GO TO 300-SET-2X2-DIVISOR.    
  * *********************************************************         
  *  IF FIRST TIME THROUGH AND YOU WANT TO BUILD A SEED.    *
  * ********************************************************* 
       IF COUNT-OF-ACCESSES = ZERO AND RANDOM-NUMBER = ZERO
          COMPUTE RANDOM-NUMBER-BUILT =
                ((SECONDS * HOURS * MINUTES * MS) + HIGH-RANGE).
       IF COUNT-OF-ACCESSES = ZERO        
         DISPLAY 'SEED TIME ' SEED-TIME 
               ' RANDOM-NUMBER-BUILT ' RANDOM-NUMBER-BUILT 
               ' LOW-RANGE  ' LOW-RANGE.          
  * *********************************************     
  *    END OF BUILDING A SEED IF YOU WANTED TO  * 
  * *********************************************               
  * ***************************************************
  * THIS PROCESS IS WHERE THE RANDOM-NUMBER IS BUILT  *  
  * ***************************************************   
   400-RANDGEN-FORMULA.
       COMPUTE FIRST-PART = (5 * RANDOM-NUMBER-BUILT) + 7.
       DIVIDE FIRST-PART BY 2X2 GIVING WORKING-NUMBER 
         REMAINDER RANDOM-NUMBER-BUILT. 
       IF RANDOM-NUMBER-BUILT > LOW-RANGE AND
          RANDOM-NUMBER-BUILT < (HIGH-RANGE + 1)
         GO TO 600-RANDGEN-CLEANUP.
       GO TO 400-RANDGEN-FORMULA.
  * *********************************************     
  *    GOOD RANDOM NUMBER HAS BEEN BUILT        *               
  * *********************************************
   600-RANDGEN-CLEANUP.
       ADD 1 TO COUNT-OF-ACCESSES.
       COMPUTE RANDOM-NUMBER = 
            RANDOM-NUMBER-BUILT - LOW-RANGE. 
  * *******************************************************
  * THE NEXT 3 LINE OF CODE ARE FOR TESTING  ON CONSOLE   *  
  * *******************************************************
       DISPLAY RANDOM-NUMBER.
       IF COUNT-OF-ACCESSES < RANDOM-NUMBERS-NEEDED
        GO TO 100-RANDGEN-EDIT-HOUSEKEEPING.     
   900-EXIT-RANDGEN.
       IF RANDOM-MSG NOT = SPACE
        DISPLAY 'RANDOM-MSG: ' RANDOM-MSG.
        MOVE ZERO TO COUNT-OF-ACCESSES RANDOM-NUMBERS-NEEDED RANDOM-NUMBER. 
        MOVE SPACE TO YOU-PROVIDE-SEED RUN-AGAIN.
       DISPLAY 'RUN AGAIN Y OR N '
         NO ADVANCING.
       ACCEPT RUN-AGAIN.
       IF (RUN-AGAIN = 'Y' OR 'y')
         GO TO 100-RANDGEN-EDIT-HOUSEKEEPING.
       ACCEPT PAUSE-FOR-A-SECOND.
       GOBACK.

1
मुझे नहीं पता कि क्या यह वास्तव में ओपी की जरूरतों को पूरा कर सकता है, लेकिन एक कॉबोल योगदान के लिए सहारा!
मैक

1

यहां अधिकांश उत्तर यह गारंटी देने में विफल हैं कि वे एक ही नंबर को दो बार वापस नहीं करेंगे। यहाँ एक सही समाधान है:

int nrrand(void) {
  static int s = 1;
  static int start = -1;
  do {
    s = (s * 1103515245 + 12345) & 1023;
  } while (s >= 1001);
  if (start < 0) start = s;
  else if (s == start) abort();

  return s;
}

मुझे यकीन नहीं है कि बाधा अच्छी तरह से निर्दिष्ट है। एक मान लेता है कि 1000 अन्य आउटपुट के बाद एक मान को दोहराने की अनुमति है, लेकिन वह भोलेपन से 0 का तुरंत पालन करने की अनुमति देता है, जब तक कि वे दोनों अंत में दिखाई देते हैं और 1000 के सेट के शुरू होते हैं। इसके विपरीत, जबकि इसकी दूरी बनाए रखना संभव है पुनरावृत्ति के बीच 1000 अन्य मूल्य, ऐसा करने से एक ऐसी स्थिति उत्पन्न होती है जहां अनुक्रम हर बार उसी तरह से खुद को दोहराता है क्योंकि उस सीमा के बाहर कोई अन्य मूल्य नहीं होता है।

यहां एक विधि है जो हमेशा एक मूल्य को दोहराया जाने से पहले कम से कम 500 अन्य मूल्यों की गारंटी देता है:

int nrrand(void) {
  static int h[1001];
  static int n = -1;

  if (n < 0) {
    int s = 1;
    for (int i = 0; i < 1001; i++) {
      do {
        s = (s * 1103515245 + 12345) & 1023;
      } while (s >= 1001);
      /* If we used `i` rather than `s` then our early results would be poorly distributed. */
      h[i] = s;
    }
    n = 0;
  }

  int i = rand(500);
  if (i != 0) {
      i = (n + i) % 1001;
      int t = h[i];
      h[i] = h[n];
      h[n] = t;
  }
  i = h[n];
  n = (n + 1) % 1001;

  return i;
}

यह एक LCG है, जैसे कि stackoverflow.com/a/196164/648265 , दृश्यों के लिए गैर-यादृच्छिक और साथ ही अन्य संबंधित किंक भी समान हैं।
ivan_pozdeev

@ivan_pozdeev मेरा एक LCG से बेहतर है क्योंकि यह सुनिश्चित करता है कि यह 1001st कॉल पर एक डुप्लिकेट वापस नहीं करेगा।
sh1

1

जब N 1000 से अधिक होता है और आपको K यादृच्छिक नमूने खींचने की आवश्यकता होती है, तो आप एक सेट का उपयोग कर सकते हैं जिसमें अब तक के नमूने हैं। प्रत्येक ड्रॉ के लिए आप अस्वीकृति नमूने का उपयोग करते हैं , जो एक "लगभग" O (1) ऑपरेशन होगा, इसलिए कुल चलने का समय O (N) स्टोरेज के साथ लगभग O (K) है।

यह एल्गोरिथ्म टकरावों में चलता है जब K "N" के पास होता है। इसका मतलब है कि रनिंग टाइम O (K) से बहुत अधिक खराब होगा। एक साधारण फिक्स तर्क को उल्टा करना है ताकि, K> N / 2 के लिए, आप उन सभी नमूनों का रिकॉर्ड रखें जो अभी तक नहीं खींचे गए हैं। प्रत्येक ड्रॉ रिजेक्शन सेट से एक नमूना निकालता है।

अस्वीकृति के नमूने के साथ अन्य स्पष्ट समस्या यह है कि यह ओ (एन) स्टोरेज है, जो कि खराब खबर है यदि एन अरबों में है या अधिक है। हालाँकि, एक एल्गोरिथ्म है जो उस समस्या को हल करता है। आविष्कारक के बाद इस एल्गोरिथ्म को विटर का एल्गोरिथ्म कहा जाता है। एल्गोरिथ्म यहाँ वर्णित है । विटर के एल्गोरिथ्म का सार यह है कि प्रत्येक ड्रॉ के बाद, आप एक निश्चित वितरण का उपयोग करके एक यादृच्छिक स्किप की गणना करते हैं जो एक समान नमूनाकरण की गारंटी देता है।


दोस्तों, कृपया! फिशर-येट्स विधि टूट गई है। आप प्रायिकता 1 / N के साथ पहले वाले को चुनते हैं और दूसरे को प्रायिकता 1 / (N-1)! = 1 / N के साथ। यह एक पक्षपाती नमूना विधि है! पूर्वाग्रह को हल करने के लिए आपको वास्तव में विटर के एल्गोरिथ्म की आवश्यकता है।
इमानुएल लैंडेहोम

0

फिशर येट्स

for i from n−1 downto 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]

यह वास्तव में O (n-1) है क्योंकि आपको अंतिम दो के लिए केवल एक स्वैप की आवश्यकता है
यह C # है

public static List<int> FisherYates(int n)
{
    List<int> list = new List<int>(Enumerable.Range(0, n));
    Random rand = new Random();
    int swap;
    int temp;
    for (int i = n - 1; i > 0; i--)
    {
        swap = rand.Next(i + 1);  //.net rand is not inclusive
        if(swap != i)  // it can stay in place - if you force a move it is not a uniform shuffle
        {
            temp = list[i];
            list[i] = list[swap];
            list[swap] = temp;
        }
    }
    return list;
}

इसके साथ पहले से ही एक उत्तर है, लेकिन यह काफी लंबा घुमावदार है और यह नहीं पहचानता है कि आप 1 पर रोक सकते हैं (0 नहीं)
paparazzo

0

कृपया मेरा उत्तर देखें https://stackoverflow.com/a/46807110/8794687 देखें

यह सबसे सरल एल्गोरिदम है कि औसत समय जटिलता में से एक है हे ( रों लॉग रों ), एस नमूना आकार को संकेतित करते। हैश टेबल एल्गोरिदम में कुछ लिंक भी हैं जिनकी जटिलता ( एस ) होने का दावा किया जाता है ।


-1

किसी ने पोस्ट किया "एक्सेल में यादृच्छिक संख्या बनाना"। मैं इस आदर्श का उपयोग कर रहा हूं। 2 भागों के साथ एक संरचना बनाएं, str.index और str.ran; 10 यादृच्छिक संख्याओं के लिए 10 संरचनाओं की एक सरणी बनाएं। Str.index को 0 से 9 तक और str.ran को अलग-अलग यादृच्छिक संख्या पर सेट करें।

for(i=0;i<10; ++i) {
      arr[i].index = i;
      arr[i].ran   = rand();
}

गिरफ्तारी में मूल्यों पर सरणी को क्रमबद्ध करें [i] .ran Str.index अब एक यादृच्छिक क्रम में है। नीचे सी कोड है:

#include <stdio.h>
#include <stdlib.h>

struct RanStr { int index; int ran;};
struct RanStr arr[10];

int sort_function(const void *a, const void *b);

int main(int argc, char *argv[])
{
   int cnt, i;

   //seed(125);

   for(i=0;i<10; ++i)
   {
      arr[i].ran   = rand();
      arr[i].index = i;
      printf("arr[%d] Initial Order=%2d, random=%d\n", i, arr[i].index, arr[i].ran);
   }

   qsort( (void *)arr, 10, sizeof(arr[0]), sort_function);
   printf("\n===================\n");
   for(i=0;i<10; ++i)
   {
      printf("arr[%d] Random  Order=%2d, random=%d\n", i, arr[i].index, arr[i].ran);
   }

   return 0;
}

int sort_function(const void *a, const void *b)
{
   struct RanStr *a1, *b1;

   a1=(struct RanStr *) a;
   b1=(struct RanStr *) b;

   return( a1->ran - b1->ran );
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.