मुझे "उपयोगी" C ++ बाइनरी सर्च एल्गोरिथ्म कहां मिल सकता है?


106

मुझे एक द्विआधारी खोज एल्गोरिथ्म की आवश्यकता है जो सी ++ एसटीएल कंटेनरों के साथ संगत है, std::binary_searchमानक पुस्तकालय के <algorithm>हेडर में कुछ ऐसा है , लेकिन मुझे इसकी आवश्यकता है कि पुनरावृत्तिकर्ता जो परिणाम पर इंगित करता है, न कि एक साधारण बूलियन जो तत्व मौजूद है, मुझे बता रहा है।

(एक तरफ ध्यान दें, कि बाइनरी_सर्च के लिए एपीआई को परिभाषित करने के दौरान मानक समिति क्या सोच रही थी?)

यहां मेरी मुख्य चिंता यह है कि मुझे एक द्विआधारी खोज की गति की आवश्यकता है, इसलिए यद्यपि मैं अन्य एल्गोरिदम के साथ डेटा पा सकता हूं, जैसा कि नीचे उल्लेख किया गया है, मैं इस तथ्य का लाभ उठाना चाहता हूं कि मेरे डेटा को एक बाइनरी के लाभ प्राप्त करने के लिए हल किया गया है खोज, रैखिक खोज नहीं।

अब तक lower_boundऔर upper_boundअसफल रहा अगर डेटम गायब है:

//lousy pseudo code
vector(1,2,3,4,6,7,8,9,0) //notice no 5
iter = lower_bound_or_upper_bound(start,end,5)
iter != 5 && iter !=end //not returning end as usual, instead it'll return 4 or 6

नोट: मैं भी एक एल्गोरिथ्म का उपयोग करके ठीक हूं जो कि std नाम स्थान से संबंधित नहीं है जब तक कि कंटेनर के साथ संगत नहीं है। जैसे, कहना boost::binary_search


2
संपादित करें के बारे में: यही कारण है कि एसटीडी :: equ_range समाधान है। अन्यथा, आपको समानता (या अधिक होने के लिए समानता) के लिए परीक्षण करना होगा
ल्यूक हर्मिट्टे

आपको (निम्न / ऊपरी) _bound (नीचे उत्तर देखें) का उपयोग करने के बाद समानता के लिए परीक्षण करना होगा।
ल्यूक टॉरिल

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

@ विविड, हुर्रे! आपको सिर्फ दस्तावेज के टुकड़े के बारे में पता चला जिसकी मुझे जानकारी होनी चाहिए! धन्यवाद!
रॉबर्ट गोल्ड

रॉबर्ट, निचले / ऊपरी_बाउंड / बराबर_अनुरूप एल्गोरिदम अनारक्षित श्रेणियों के साथ काम नहीं करते हैं। आप उन्हें अपने द्वारा लिए गए तत्वों के नमूने के साथ काम करते हुए देखने के लिए भाग्यशाली हैं।
ल्यूक हरमिट

जवाबों:


97

ऐसा कोई कार्य नहीं है, लेकिन आप एक साधारण का उपयोग करके लिख सकते हैं std::lower_bound, std::upper_boundया std::equal_range

एक साधारण कार्यान्वयन हो सकता है

template<class Iter, class T>
Iter binary_find(Iter begin, Iter end, T val)
{
    // Finds the lower bound in at most log(last - first) + 1 comparisons
    Iter i = std::lower_bound(begin, end, val);

    if (i != end && !(val < *i))
        return i; // found
    else
        return end; // not found
}

एक अन्य समाधान एक का उपयोग करना होगा std::set, जो तत्वों के आदेश की गारंटी देता है और एक विधि प्रदान करता iterator find(T key)है जो दिए गए आइटम को पुनरावृत्ति देता है। हालांकि, आपकी आवश्यकताएं सेट के उपयोग के साथ संगत नहीं हो सकती हैं (उदाहरण के लिए यदि आपको एक ही तत्व को कई बार संग्रहीत करने की आवश्यकता है)।


हां यह काम करता है, और मेरे पास अभी एक समान कार्यान्वयन है, हालांकि यह "भोली" कार्यान्वयन है, इस अर्थ में कि यह स्थिति के संदर्भ का उपयोग नहीं कर रहा है, इस मामले में डेटा सॉर्ट किया गया है।
रॉबर्ट गोल्ड

5
मैं वास्तव में आपकी टिप्पणी को नहीं समझता, क्योंकि लोअरबाउंड केवल सॉर्ट किए गए डेटा पर उपयोग किया जा सकता है। खोज (संपादित देखें) का उपयोग करने की तुलना में जटिलता कम है।
ल्यूक टॉरिल

4
ल्यूक के जवाब को पूरक करने के लिए, मैट ऑस्टर्न के क्लासिक लेख की जांच करें कि आपको सेट का उपयोग क्यों नहीं करना चाहिए, और इसके बजाय आपको क्या उपयोग करना चाहिए (सी ++ रिपोर्ट 12: 4, अप्रैल 2000) यह समझने के लिए कि क्यों हल किए गए वैक्टर के साथ द्विआधारी खोज आमतौर पर एसटीडी :: सेट के लिए बेहतर है। , जो एक पेड़ आधारित सहयोगी कंटेनर है।
ज़ुनत्ज़ु

16
उपयोग न करें *i == val! बल्कि उपयोग करें !(val < *i)। इसका कारण यह है कि lower_boundउपयोग <नहीं, ==(यानी Tसमानता-तुलनीय होने के लिए भी आवश्यक नहीं है)। (देखें स्कॉट Meyers ' प्रभावी एसटीएल के बीच अंतर का एक विवरण के लिए समानता और तुल्यता ।)
gx_

1
@ CanKavaklıoğlu में कोई तत्व स्थित नहीं है end। C ++ मानक लाइब्रेरी में सीमाओं को आधे खुले अंतराल के साथ दर्शाया गया है: अंतिम तत्व के बाद अंतिम पुनरावृत्त "अंक" । जैसे, यह एल्गोरिदम द्वारा वापस किया जा सकता है यह इंगित करने के लिए कि कोई मूल्य नहीं मिला।
ल्यूक टॉरिल

9

आपकी नजर होनी चाहिए std::equal_range। यह सभी परिणामों की सीमा तक पुनरावृत्तियों की एक जोड़ी लौटाएगा।


Cplusplus.com/reference/algorithm/equal_range के अनुसार std की लागत :: बराबर_ व्यवस्था लगभग दोगुनी है जितनी std :: लोअर_बाउंड। ऐसा प्रतीत होता है कि यह std :: निचला_बाउंड के लिए कॉल और std :: ऊपरी_बाउंड के लिए एक कॉल लपेटता है। यदि आप जानते हैं कि आपके डेटा में डुप्लिकेट नहीं है, तो वह ओवरकिल और एसटीडी है :: निचला_बाउंड (जैसा कि शीर्ष उत्तर में दिखाया गया है) सबसे अच्छा विकल्प है।
ब्रूस डॉसन

@BruceDawson: cplusplus.com केवल व्यवहार को निर्दिष्ट करने के लिए एक संदर्भ कार्यान्वयन देता है ; एक वास्तविक कार्यान्वयन के लिए आप अपने पसंदीदा मानक पुस्तकालय की जांच कर सकते हैं। उदाहरण के लिए, llvm.org/svn/llvm-project/libcxx/trunk/include/algorithm में हम देख सकते हैं कि लोअरबाउंड और अपर_बाउंड के कॉल असंतुष्ट अंतराल (कुछ मैनुअल बाइनरी सर्च के बाद) पर किए जाते हैं। यह कहा जा रहा है, यह अधिक महंगा होने की संभावना है, विशेष रूप से कई मूल्यों के मेल खाने वाले पर्वतमाला पर।
मैथ्यू एम।

6

उनमें से एक सेट है:

http://www.sgi.com/tech/stl/table_of_contents.html

निम्न को खोजें:

एक अलग नोट पर:

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


3
जैसा कि मैंने पहले बताया था बाइनरी_सर्च एक पुनरावृत्तिकर्ता को वापस नहीं करता है, इसलिए मैं एक विकल्प की तलाश कर रहा हूं।
रॉबर्ट गोल्ड

1
हाँ मैं जानता हूँ। लेकिन यह बाइनरी सर्च एल्गोरिदम के सेट में फिट बैठता है। तो दूसरों के बारे में जानने के लिए अच्छा है।
मार्टिन जॉर्ज

8
बाइनरी_सर्च सिर्फ एसटीएल में कई अन्य चीजों की तरह है, जिसका नाम गलत है। मुझे उससे नफरत है। अस्तित्व के लिए परीक्षण कुछ खोजने के समान नहीं है।
ओरेगनगॉस्ट

2
ये बाइनरी खोज फ़ंक्शंस उस स्थिति में उपयोगी नहीं हैं, जब आप उस तत्व के सूचकांक को जानना चाहते हैं जिसे आप खोज रहे हैं। मुझे इस कार्य के लिए अपना स्वयं का पुनरावर्ती कार्य लिखना है। मुझे उम्मीद है कि, टेम्पलेट <class T> int bindary_search (const T & आइटम), C ++ के अगले संस्करण में जोड़ा जाना चाहिए।
केमिन झोउ

3

अगर std :: लोअर_बाउंड आपकी पसंद के लिए बहुत निम्न-स्तर है, तो आप बढ़ावा देना चाह सकते हैं :: कंटेनर :: flat_multiset । यह एसटी के लिए एक ड्रॉप-इन प्रतिस्थापन है: बाइनरी सर्च का उपयोग करके सॉर्ट किए गए वेक्टर के रूप में कार्यान्वित मल्टीसेट।


1
अच्छा लिंक; और लिंक में भी अच्छा लिंक : lafstern.org/matt/col1.pdf , जो बताता है कि कैसे हल किए गए वेक्टर के साथ लागू किए गए लुकअप सेट के बजाय (हालांकि दोनों लॉग (एन) हैं), आनुपातिकता के काफी बेहतर स्थिरांक हैं और ~ हैं दो बार तेजी से (नुकसान एक बड़ा समय होने के नाते)।
डैन निसेनबूम

2

सबसे छोटा कार्यान्वयन, सोच रहा था कि इसे मानक पुस्तकालय में शामिल क्यों नहीं किया गया है:

template<class ForwardIt, class T, class Compare=std::less<>>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
{
    // Note: BOTH type T and the type after ForwardIt is dereferenced 
    // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. 
    // This is stricter than lower_bound requirement (see above)

    first = std::lower_bound(first, last, value, comp);
    return first != last && !comp(value, *first) ? first : last;
}

से https://en.cppreference.com/w/cpp/algorithm/lower_bound


मैं दो कारणों से सोच सकता हूं कि यह मानक पुस्तकालय में नहीं है: उन्हें लगता है कि इसे लागू करना आसान है, लेकिन प्रमुख कारण शायद यह है कि इसके लिए ऑपरेटर () () का उलटा संस्करण आवश्यक हो सकता है यदि मूल्य पहले * के साथ विनिमेय नहीं है।
user877329

1

इस फ़ंक्शन की जाँच करें, qBinaryFind :

RandomAccessIterator qBinaryFind ( RandomAccessIterator begin, RandomAccessIterator end, const T & value )

रेंज की एक द्विआधारी खोज करता है [शुरू, अंत) और मूल्य की घटना की स्थिति देता है। यदि मूल्य की कोई घटना नहीं होती है, तो रिटर्न समाप्त होता है।

श्रेणी [शुरू, अंत) में वस्तुओं को आरोही क्रम में क्रमबद्ध किया जाना चाहिए; देखें qSort ()।

यदि एक ही मूल्य की कई घटनाएं होती हैं, तो उनमें से किसी को भी लौटाया जा सकता है। यदि आपको बेहतर नियंत्रण की आवश्यकता है तो qLowerBound () या qUpperBound () का उपयोग करें।

उदाहरण:

QVector<int> vect;
 vect << 3 << 3 << 6 << 6 << 6 << 8;

 QVector<int>::iterator i =
         qBinaryFind(vect.begin(), vect.end(), 6);
 // i == vect.begin() + 2 (or 3 or 4)

फ़ंक्शन को <QtAlgorithms>हेडर में शामिल किया गया है जो Qt लाइब्रेरी का एक हिस्सा है ।


1
दुर्भाग्य से यह एल्गोरिथ्म STL कंटेनरों के साथ संगत नहीं है।
बार्टोलो-ओटिट जूल 30'13


0
int BinarySearch(vector<int> array,int var)
{ 
    //array should be sorted in ascending order in this case  
    int start=0;
    int end=array.size()-1;
    while(start<=end){
        int mid=(start+end)/2;
        if(array[mid]==var){
            return mid;
        }
        else if(var<array[mid]){
            end=mid-1;
        }
        else{
            start=mid+1;
        }
    }
    return 0;
}

उदाहरण: किसी सरणी पर विचार करें, A = [1,2,3,4,5,6,7,8,9] मान लीजिए कि आप प्रारंभ में 3 का सूचकांक खोजना चाहते हैं, = 0 शुरू करें और अंत = 9-1 = 8 अब शुरू करें , शुरू होने के बाद से <= अंत; मध्य = 4; (सरणी [मध्य] जो ५ है)! = ३ अब, ३ मध्य से बाईं ओर स्थित है, क्योंकि यह ५ से छोटा है। इसलिए, हम केवल सरणी के बाएं भाग को खोजते हैं, इसलिए अब = ० और अंत = ३ शुरू करें; mid = 2.Since array [mid] == 3, इसलिए हमें वह नंबर मिला जिसकी हम खोज कर रहे थे। इसलिए, हम इसका सूचकांक लौटाते हैं जो मध्य के बराबर है।


1
कोड होना अच्छा है, लेकिन आप उन लोगों के लिए संक्षिप्त विवरण प्रदान करके उत्तर को बेहतर बना सकते हैं जो भाषा के लिए नए हैं।
तायगास्त

किसी ने गलत तरीके से आपकी पोस्ट को निम्न-गुणवत्ता के रूप में चिह्नित किया । एक ही कोड-जवाब कम गुणवत्ता वाले नहीं है । क्या यह प्रश्न का उत्तर देने का प्रयास करता है? यदि नहीं, तो 'उत्तर नहीं' के रूप में चिह्नित करें या विलोपन की अनुशंसा करें (यदि समीक्षा पंक्ति में)। ख) क्या यह तकनीकी रूप से गलत है? नीचा दिखाना या टिप्पणी करना।
वाई हा ली

0

श्रेणी के अंदर स्थिति को लौटाने वाला एक समाधान इस तरह हो सकता है, केवल पुनरावृत्तियों पर संचालन का उपयोग करके (यह काम करना चाहिए, भले ही पुनरावृत्ति अंकगणित न हो):

template <class InputIterator, typename T>
size_t BinarySearchPos(InputIterator first, InputIterator last, const T& val)
{       
    const InputIterator beginIt = first;
    InputIterator element = first;
    size_t p = 0;
    size_t shift = 0;
    while((first <= last)) 
    {
        p = std::distance(beginIt, first);
        size_t u = std::distance(beginIt, last);
        size_t m = p + (u-p)/2;  // overflow safe (p+u)/2
        std::advance(element, m - shift);
        shift = m;
        if(*element == val) 
            return m; // value found at position  m
        if(val > *element)
            first = element++;
        else
            last  = element--;

    }
    // if you are here the value is not present in the list, 
    // however if there are the value should be at position u
    // (here p==u)
    return p;

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