2011-05-19 5 views
15

मैं वर्तमान में एक समस्या पर काम कर रहा हूं जिसके लिए एक सेट से किसी तत्व के यादृच्छिक चयन की आवश्यकता होती है। प्रत्येक तत्व में वजन (चयन संभावना) से जुड़ा होता है।मूल्यों के बहुत बड़े सेट से तेजी से भारित यादृच्छिक चयन

मेरी समस्या यह है कि तत्वों की एक छोटी संख्या के साथ सेट के लिए 5-10 कहते हैं, समाधान की जटिलता (चलने का समय) स्वीकार्य था, हालांकि तत्वों की संख्या 1K या 10K आदि के लिए कहती है, चलने का समय अस्वीकार्य हो जाता है।

मेरे वर्तमान रणनीति है:

  1. श्रृंखला के साथ यादृच्छिक मान एक्स का चयन करें [0,1)
  2. दोहराएं तत्वों उनके वजन संक्षेप जब तक योग
  3. तत्व है जो योग की वजह से एक्स से अधिक है एक्स से अधिक होने के लिए चुना गया है और

बड़े सेटों और चयनों की एक बड़ी संख्या के लिए यह प्रक्रिया वर्गबद्ध व्यवहार को प्रदर्शित करने के लिए शुरू होती है, संक्षेप में एक तेज़ तरीका है? शायद एक बेहतर एल्गोरिदम?

+0

आपको सी ++ टैग को हटा देना चाहिए, क्योंकि यह किसी भी भाषा पर लागू एक सामान्य एल्गोरिदम प्रश्न है। – dkamins

+5

सच है, लेकिन मैं सी ++ में समाधान पसंद करूंगा, क्योंकि जिस समस्या को मैं कोडिंग कर रहा हूं वह C++ –

उत्तर

11

मानते हैं कि तत्व भार तय किए गए हैं, आप प्रीकंप्यूटेड रकम के साथ काम कर सकते हैं। यह घनत्व समारोह की बजाय सीधे संचयी संभाव्यता फ़ंक्शन के साथ काम करने जैसा है।

लुकअप को बाइनरी खोज के रूप में कार्यान्वित किया जा सकता है, और इसलिए तत्वों की संख्या में लॉग (एन) होना चाहिए।

एक द्विआधारी खोज को वजन के कंटेनर को यादृच्छिक_एक्स की आवश्यकता होती है।

वैकल्पिक रूप से, std::map<> और upper_bound() विधि का उपयोग करें।

#include <iostream> 
#include <map> 
#include <stdlib.h> 

int main() 
{ 
    std::map<double, char> cumulative; 
    typedef std::map<double, char>::iterator It; 

    cumulative[.20]='a'; 
    cumulative[.30]='b'; 
    cumulative[.40]='c'; 
    cumulative[.80]='d'; 
    cumulative[1.00]='e'; 

    const int numTests = 10; 
    for(int i = 0; 
     i != numTests; 
     ++i) 
    { 
     double linear = rand()*1.0/RAND_MAX; 
     std::cout << linear << "\t" << cumulative.upper_bound(linear)->second << std::endl; 
    } 

    return 0; 
} 
+1

में है जिसका मतलब है कि stl upper_bound low_bound का उपयोग करें? क्या आप एक त्वरित उदाहरण प्रदान कर सकते हैं? –

+1

@ कुर्ज़न: अपने सभी तत्वों को वजन देने के बजाय, अपने कोड पर कीथ के सुझाव को लागू करने के लिए, वजन + पिछले वजन की राशि असाइन करें। फिर, एक यादृच्छिक मान एक्स [0,1) का चयन करें, और उस तत्व के लिए एक इटरेटर प्राप्त करने के लिए set :: lower_bound का उपयोग करें जिसका मान __ से कम नहीं है। (वैकल्पिक रूप से, यदि ऊपरी_बाउंड का उपयोग करें तो तत्व X से सख्ती से अधिक होना चाहिए) – decltype

+0

@decltype: उस टिप के लिए धन्यवाद! –

15

आप वॉकर एल्गोरिदम का उपयोग करना चाहते हैं। एन तत्वों के साथ, ओ (एन) की एक सेट-अप लागत है। हालांकि, नमूना लागत ओ (1) है।

  • ए जे वाकर, असतत यादृच्छिक चर और जनरल वितरण, एसीएम TOMS 3, 253-256 (1977) उत्पन्न करने के लिए एक कुशल विधि देखें।
  • Knuth, TAOCP, वॉल्यूम 2, सेक्शन 3.4.1.ए.

a RandomLib की RandomSelect वर्ग इस एल्गोरिथ्म लागू करता है।

+3

ओपी में मदद करने में थोड़ा देर हो चुकी है, लेकिन भविष्य के पाठकों के लिए, यह सही जवाब है। एक ओ (1) एल्गोरिदम सप्ताह के किसी भी दिन ओ (लॉग एन) एल्गोरिदम से बेहतर होता है, –

+0

सी ++ 11 से: http://en.cppreference.com/w/cpp/numeric/random/discrete_distribution – leezu

1

यदि आपके पास एक यादृच्छिक तत्व को समान रूप से नमूना देने का एक त्वरित तरीका है, तो आप अस्वीकृति नमूनाकरण का उपयोग कर सकते हैं; आपको केवल इतना जानने की जरूरत है कि अधिकतम वजन है। यह निम्नानुसार काम करेगा: मान लें कि अधिकतम वजन एम है। [0,1] में एक संख्या एक्स को समान रूप से चुनें। नमूना तत्व बार-बार जब तक आप उस व्यक्ति को नहीं पाते जिसका वजन कम से कम एम * एक्स है; इसे चुनें

या, अनुमानित समाधान: यादृच्छिक रूप से 100 तत्वों को समान रूप से चुनें; इस सेट के भीतर वजन के अनुपात में एक आनुपातिक चुनें।

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