2011-08-26 2 views
6

आज कुछ कोड लिखने में, मैंने एक परिस्थिति पर ऐसा किया है जिसने मुझे एक तरह की बाइनरी खोज लिखने के लिए प्रेरित किया है जिसे मैंने कभी नहीं देखा है। क्या इस बाइनरी खोज का नाम है, और क्या यह वास्तव में एक "बाइनरी" खोज है?क्या इस प्रकार की बाइनरी खोज के लिए कोई नाम है?

प्रेरणा

सबसे पहले, क्रम खोज को समझने के लिए आसान बनाने के लिए, मैं उपयोग के मामले कि इसके निर्माण के पैदा की व्याख्या करेगा।

कहें कि आपके पास आदेशित संख्याओं की एक सूची है। आपको उस सूची में संख्या का सूचकांक ढूंढने के लिए कहा जाता है जो x के सबसे नज़दीक है।

int findIndexClosestTo(int x); 

कॉल करने के लिए findIndexClosestTo()हमेशा इस नियम का पालन करें:

तो findIndexClosestTo() के अंतिम परिणाम i था, तो i के करीब के लिए वर्तमान कॉल का परिणाम होने का अधिक से अधिक संभावना सूचकांक होते हैं findIndexClosestTo()

दूसरे शब्दों में, इस सूचकांक को हमें इस समय खोजने की आवश्यकता है जो हमने उससे आगे की तुलना में आखिरी बार के करीब होने की संभावना है।

उदाहरण के लिए, एक अनुरूपित लड़का की कल्पना करें जो स्क्रीन पर बाएं और दाएं चलती है। अगर हम अक्सर लड़के के स्थान की अनुक्रमणिका से पूछताछ कर रहे हैं, तो संभवतः वह उस अंतिम स्थान के पास कहीं है जहां हमने उसे पाया था।

एल्गोरिथ्म

उपरोक्त मामले को देखते हुए, हम जानते हैं कि findIndexClosestTo() के अंतिम परिणाम i था (यदि यह वास्तव में पहली बार समारोह बुलाया गया है है, सूची के बीच सूचकांक, सादगी के लिए करने के लिए i चूक, हालांकि पहली कॉल के परिणाम को खोजने के लिए एक अलग बाइनरी खोज वास्तव में तेज होगी), और फ़ंक्शन को फिर से बुलाया गया है। नया नंबर x देखते हुए, हम अपने सूचकांक खोजने के लिए इस एल्गोरिथ्म का पालन करें:

  1. interval = 1;
  2. संख्या हम के लिए, x देख रहे हैं, i पर तैनात है? यदि ऐसा है, तो i लौटाएं;
  3. यदि नहीं, तो निर्धारित करें कि xi से ऊपर या नीचे है या नहीं। (याद रखें, सूची क्रमबद्ध है।)
  4. की दिशा में interval सूचकांक ले जाएं।
  5. यदि हमें हमारे नए स्थान पर x मिल गया है, तो उस स्थान को वापस करें।
  6. डबल interval। (यानी interval *= 2)
  7. हम x बीत चुके हैं, वापस interval सूचकांक जाना, interval = 1 निर्धारित करते हैं, 4.

संभावना नियम (प्रेरणा शीर्षक के अंतर्गत) ऊपर कहा गया है को देखते हुए जाने के लिए, यह होने के लिए मुझे ऐसा लगता है सही सूचकांक खोजने का सबसे प्रभावी तरीका। क्या आप तेजी से जानते हैं?

+0

मुझे लगता है कि यह वास्तव में एक सरणी है और सूची नहीं है? क्योंकि सूची में बाइनरी खोज बेवकूफ होगी। – Nemo

+1

मुझे लगता है कि सबसे अच्छा जवाब इस बात पर निर्भर करेगा कि i पर आधारित स्थिति के लिए संभाव्यता वितरण क्या है। उदाहरण के लिए यदि 99% मौका है जो कि 3 में से एक है तो एक बहुत ही अलग उत्तर उपयोगी होगा यदि यह कहीं भी 0.001% अधिक होने की संभावना है। मुझे लगता है कि इष्टतम उत्तर एक संभाव्यता आधारित वितरण होगा जैसे बाइनरी खोज एक ऐसी जगह चुनती है जो प्रत्येक तरफ वांछित वस्तु का 50% मौका देती है। तो यदि आप संभाव्यता वक्र को परिभाषित कर सकते हैं तो आप शायद एक सुंदर अच्छा एल्गोरिदम परिभाषित कर सकते हैं। – Chris

+0

@Chris बहुत अच्छा बिंदु। यदि सभी डेटा बिंदु _nearly_ संभावना में बराबर थे, तो यह नियमित बाइनरी खोज से भी बदतर होगा। मेरे मामले में, संभावना है कि आप आखिरी बिंदु से आगे बढ़ने के बाद तेजी से क्षय हो जाते हैं, इस मामले में, मेरा मानना ​​है कि यह खोज तेज़ है। –

उत्तर

3

क्या आप कर रहे हैं (IMHO) Interpolation search

का एक संस्करण एक प्रक्षेप खोज में आप मान संख्या समान रूप से वितरित कर रहे हैं है, और पहले और अंतिम संख्या और सरणी की लंबाई से किसी संख्या का स्थान अनुमान लगाने का प्रयास करें।

अपने मामले में, आप इंटरपोलेशन-अलगो को संशोधित कर रहे हैं जैसे कि आप मानते हैं कि कुंजी आपके द्वारा खोजे गए अंतिम नंबर के बहुत करीब है।

यह भी ध्यान रखें कि आपका अलगाव अलगो के समान है जहां टीसीपी इष्टतम पैकेट आकार खोजने की कोशिश करता है। अंतराल

  • (नाम याद न :()

    1. प्रारंभ धीमी
      1. डबल अगर पैकेट में विफल रहता है पुनः आरंभ पिछले से packet./ डिफ़ॉल्ट पैकेट आकार .. 3 से पुन: प्रारंभ करें सफल रहा।
  • 0

    यह मेरे सिर के ऊपर से बात कर रहा है, इसलिए मेरे पास इसे वापस करने के लिए कुछ भी नहीं है लेकिन आंत महसूस कर रहा है!

    चरण 7 में, यदि हम x पारित कर दिया गया है, यह interval को आधा करने के लिए, और x की ओर लौट तेजी से हो सकता है - प्रभावी ढंग से, interval = -(interval/2), बल्कि करने के लिए 1.

    interval रीसेट करने की तुलना में मैं स्केच करना होगा कागज पर कुछ संख्याओं के बाहर, हालांकि ...

    संपादित करें: क्षमा करें - मैं ऊपर बकवास बात कर रहा हूं: मुझे अनदेखा करें! (और मैं दूर जाऊंगा और उचित इस बार इसके बारे में सोचें ...)

    4

    सबसे खराब स्थिति में, आपका एल्गोरिदम ओ ((लॉग एन)^2) है।

    मान लीजिए आप 0 पर (अंतराल के साथ = 1) शुरू करते हैं, और मूल्य आप वास्तव में चाहते हैं स्थान 2 में रहता है^n - 1.

    सबसे पहले आप की जाँच करेगा 1, 2, 4, 8, ... , 2^(एन -1), 2^एन। ओह, जो overshoots, तो 2^(एन -1) पर वापस जाओ।

    अगला आप 2^(एन -1) +1, 2^(एन -1) +2, ..., 2^(एन -1) + 2^(एन -2), 2^(n-1) + 2^(n-1)। वह अंतिम शब्द 2^एन है, तो व्हाउप्स, वह फिर से ओवरशॉट। 2^(एन -1) + 2^(एन -2) पर वापस जाएं।

    और इसी तरह, जब तक आप अंततः तक पहुँचने के 2^(n-1) + 2^(n-2) + ... + 1 == 2^n - 1.

    पहले overshoot लॉग ले लिया एन कदम अगले ने (लॉग एन) -1 कदम उठाए। अगला लिया (लॉग एन) - 2 कदम। और इसी तरह।

    तो, सबसे खराब मामला, आपने 1 + 2 + 3 + लिया ... + लॉग एन == ओ ((लॉग एन)^2) चरण।

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

    मुझे इस एल्गोरिदम के लिए कोई नाम नहीं पता, लेकिन मुझे यह पसंद है। तो आप (एक विचित्र संयोग से, मैं यह कल का इस्तेमाल किया जा सकता था है। वास्तव में।)

    +0

    इंटरपोलेशन यह है। और यदि आप एक बड़े सरणी (एन> 1024) से निपट रहे हैं तो इंटरपोलेशन आम तौर पर द्विआधारी से बेहतर होगा। एन> 10000 के लिए, यह बहुत तेज़ होगा। –

    1

    आपका दिनचर्या प्रक्षेप दिनचर्या की खासियत है। यदि आप इसे यादृच्छिक संख्या (~ मानक बाइनरी खोज) के साथ कहते हैं तो आप अधिक खोना नहीं चाहते हैं, लेकिन यदि आप धीरे-धीरे बढ़ती संख्या के साथ इसे कॉल करते हैं, तो सही सूचकांक को ढूंढने में लंबा समय नहीं लगेगा।

    इसलिए यह इंटरपोलेशन उद्देश्यों के लिए ऑर्डर की गई तालिका को खोजने के लिए एक समझदार डिफ़ॉल्ट व्यवहार है।

    इस विधि पर न्यूमेरिकल व्यंजनों 3 संस्करण, खंड 3.1 में बड़ी लंबाई के साथ चर्चा की गई है।