আমি কোথায় একটি "দরকারী" বাইনারি অনুসন্ধান অ্যালগরিদম পেতে পারি?


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

দ্রষ্টব্য: আমি এমন একটি অ্যালগরিদম ব্যবহার করে জরিমানা করছি যেটি কনটেইনারগুলির সাথে সামঞ্জস্য হওয়া অবধি স্টাড নেমস্পেসের সাথে সম্পর্কিত নয়। লাইক, বলুন boost::binary_search,।


2
সম্পাদনা সম্পর্কিত: এজন্যই std :: برابر_আরজই হল সমাধান। অন্যথায়, আপনাকে সাম্যতার জন্য পরীক্ষা করতে হবে (বা আরও বেশি হওয়ার সমতুল্যতা)
লুস হার্মিটে

(নিম্ন / উপরের) _বাউন্ড (নীচের উত্তর দেখুন) ব্যবহারের পরে আপনাকে সমতার জন্য পরীক্ষা করতে হবে।
লুক টুরাইল

লোয়ার_বাউন্ড এবং আপার_বাউন্ড ডকুমেন্টেশন সূচিত করে যে রেঞ্জটি বাছাই করতে হবে এবং এর কারণে এগুলি বাইনারি অনুসন্ধান হিসাবে প্রয়োগ করা যেতে পারে।
ভিভিডোস

@ ভিভিডোস, হুররে! আপনি যে ডকুমেন্টেশনের টুকরোটি সম্পর্কে আমার জানা দরকার তা খুঁজে পেয়েছেন! ধন্যবাদ!
রবার্ট গোল্ড 11

রবার্ট, নিম্ন / উপরের_বাউন্ড / সমতুল্য_আরেজ অ্যালগরিদমগুলি অরসোর্টড রেঞ্জের সাথে কাজ করে না। আপনি গ্রহণ করেছেন এমন উপাদানগুলির নমুনার সাথে তাদের কাজ করে দেখলে আপনি কেবল ভাগ্যবান।
লুক হার্মিটে

উত্তর:


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
আমি আপনার মন্তব্যটি সত্যই বুঝতে পারি না, যেহেতু লোয়ার_বাউন্ড কেবলমাত্র সাজানো ডেটাতেই ব্যবহার করা যেতে পারে। জটিলতাটি (ব্যবহার সম্পাদনা দেখুন) ব্যবহারের চেয়ে কম।
লুক টুরাইল 11

4
লুসের জবাবের পরিপূরক হিসাবে , সাজানো ভেক্টরগুলির সাথে বাইনারি অনুসন্ধান কেন সাধারণত স্টাড :: সেটকে কেন পছন্দ করা যায় তা বোঝার জন্য ম্যাট আস্টার্নের ক্লাসিক নিবন্ধটি কেন আপনার সেট ব্যবহার করা উচিত নয় এবং তার পরিবর্তে আপনার কী ব্যবহার করা উচিত তা পরীক্ষা করুন (সি ++ রিপোর্ট 12: 4, এপ্রিল 2000) যা একটি গাছ-ভিত্তিক সাহসী ধারক।
জুনটজু

16
ব্যবহার করবেন না *i == val! বরং ব্যবহার !(val < *i)। কারণ যে lower_boundব্যবহারসমূহ <না ==(অর্থাত Tএমনকি সমতা-তুলনীয় হওয়া প্রয়োজন হয় না)। (দেখুন স্কট মায়ার্স ' কার্যকর STL মধ্যে পার্থক্য একটি ব্যাখ্যা জন্য সমতা এবং সমানতা ।)
gx_

1
@ CanKavaklıoğlu এ অবস্থিত কোনও উপাদান নেই end। সি ++ স্ট্যান্ডার্ড লাইব্রেরির ব্যাপ্তিগুলি অর্ধ-খোলা অন্তরগুলির সাথে উপস্থাপিত হয়: শেষ উপাদানটির পরে শেষ পুনরাবৃত্তি "পয়েন্ট" । যেমন, কোনও মান খুঁজে পাওয়া যায় না তা বোঝাতে এটি অ্যালগরিদম দ্বারা ফিরে আসতে পারে।
লুক টুরাইল 21

9

আপনার এক নজর করা উচিত std::equal_range। এটি সমস্ত ফলাফলের পরিসরে একজোড়া পুনরাবৃত্তি করবে।


সিপিপ্লসপ্লাস / রেফারেন্স / অ্যালগরিদম / ইক্যুয়াল_রেঞ্জ অনুযায়ী স্টাড :: সমান_আরজ স্টাড :: কম_বাউন্ডের চেয়ে প্রায় দ্বিগুণ। দেখা যাচ্ছে যে এটি স্ট্যান্ড :: লোয়ার_বাউন্ডে একটি কল এবং স্ট্যান্ড :: আপার_বাউন্ডে একটি কলটি মোড়বে। যদি আপনি জানেন যে আপনার ডেটাতে নকল নেই তবে তা ওভারকিল এবং স্টাড :: নিম্ন_বাউন্ড (শীর্ষের উত্তরে প্রদর্শিত হিসাবে) সেরা পছন্দ।
ব্রুস ডসন

@ ব্রুসডাউসন: সিপিপ্লসপ্লাস ডট কম কেবল একটি আচরণ উল্লেখ করার জন্য একটি রেফারেন্স বাস্তবায়ন দেয় ; প্রকৃত বাস্তবায়নের জন্য আপনি আপনার প্রিয় স্ট্যান্ডার্ড লাইব্রেরিটি পরীক্ষা করতে পারেন। উদাহরণস্বরূপ, llvm.org/svn/llvm-project/libcxx/trunk/incolve/algorithm এ আমরা দেখতে পাই যে লোয়ার_বাউন্ড এবং আপার_বাউন্ডে কলগুলি ডিসঅজয়েন্ট ইন্টারভ্যালে (কিছু ম্যানুয়াল বাইনারি অনুসন্ধানের পরে) করা হয়। বলা হচ্ছে, এটি আরও ব্যয়বহুল হওয়ার সম্ভাবনা রয়েছে, বিশেষত একাধিক মানের সাথে মিল রয়েছে।
ম্যাথিউ এম।

6

তাদের একটি সেট রয়েছে:

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

সন্ধান করা:

একটি পৃথক নোটে:

তারা সম্ভবত ভেবেছিল যে অনুসন্ধানের ধারকরা একাধিক ফলাফল নির্ধারণ করতে পারে। তবে সেই অদ্ভুত উপলক্ষে যেখানে আপনাকে কেবল অস্তিত্বের জন্য পরীক্ষা করা দরকার এটি একটি অনুকূলিত সংস্করণও দুর্দান্ত হবে।


3
বাইনারি_সার্চ আমি পূর্বে উল্লিখিত হিসাবে পুনরাবৃত্তি ফিরিয়ে দেয় না, এজন্যই আমি বিকল্প খুঁজছি।
রবার্ট গোল্ড

1
হ্যা আমি জানি. তবে এটি বাইনারি অনুসন্ধান অ্যালগরিদমের সেটগুলিতে ফিট করে। সুতরাং এটি সম্পর্কে অন্যদের জানার জন্য দুর্দান্ত।
মার্টিন ইয়র্ক

8
বাইনারি_সার্চটি ঠিক এসটিএল-তে থাকা অন্যান্য অনেক জিনিসের মতোই, ভুলটির নাম দেওয়া হয়েছে। আমি ওটা ঘৃণা করি. অস্তিত্বের জন্য পরীক্ষা করা কোনও কিছুর সন্ধানের মতো নয়।
ওরেগনহোস্ট

2
আপনি যে উপাদানটির সন্ধান করছেন সেটির সূচিটি জানতে চাইলে এই বাইনারি অনুসন্ধান ফাংশনগুলি কার্যকর হয় না। এই কাজের জন্য আমাকে নিজের পুনরাবৃত্ত ফাংশনটি লিখতে হবে। আমি আশা করি এটি, টেমপ্লেট <ক্লাস টি> ইন বাইন্ডারি_আরচ (কনস্ট টি এবং আইটেম), সি ++ এর পরবর্তী সংস্করণে যুক্ত করা উচিত।
কেমিন ঝো

3

আপনার পছন্দ অনুসারে যদি std :: নিম্ন_বাউন্ডটি খুব নিম্ন-স্তরের হয় তবে আপনি বুস্ট :: ধারক :: ফ্ল্যাট_মুলিটসেট পরীক্ষা করতে চাইতে পারেন । বাইনারি অনুসন্ধান ব্যবহার করে সাজানো ভেক্টর হিসাবে প্রয়োগ করা std :: মাল্টিসিটের জন্য এটি একটি ড্রপ-ইন প্রতিস্থাপন।


1
ভাল লিঙ্ক; এবং ভাল লিংক মধ্যে লিঙ্ক: lafstern.org/matt/col1.pdf , যা বর্ণনা করে কিভাবে লুক-, একটি সাজানো ভেক্টর সঙ্গে বাস্তবায়িত বরং সেট চেয়ে (যদিও উভয় লগ (এন) হয়), have উল্লেখযোগ্যভাবে আনুপাতিকতা ভালো ধ্রুবক এবং হয় ~ দ্বিগুণ দ্রুত (অসুবিধাটি বৃহত্তর অন্তর্ভুক্তির সময় হ'ল)।
ড্যান নিসেনবাউম

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.cppreferences.com/w/cpp/algorithm/lower_bound থেকে


আমি দুটি কারণ বিবেচনা করতে পারি এটি স্ট্যান্ডার্ড লাইব্রেরিতে নেই: তারা মনে করে এটি কার্যকর করা সহজ, তবে এর প্রধান কারণ সম্ভবত এটি প্রথম * এর সাথে বিনিময়যোগ্য না হলে অপারেটর () () এর বিপরীত সংস্করণ প্রয়োজন হতে পারে।
ব্যবহারকারীর 877329

1

এই ফাংশনটি দেখুন, কিউনারিফাইন্ড :

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

পরিসীমাটির একটি বাইনারি অনুসন্ধান সম্পাদন করে [শুরু, শেষ) এবং মান সংঘটনটির অবস্থান প্রদান করে। যদি মানটির কোনও ঘটনা না ঘটে তবে রিটার্ন শেষ হয়।

সীমার আইটেমগুলি [শুরু, শেষ) অবশ্যই আরোহী ক্রমে বাছাই করা উচিত; qSort () দেখুন।

যদি একই মানটির অনেকগুলি ঘটনা ঘটে থাকে তবে তাদের মধ্যে যে কোনও একটিই ফেরত যেতে পারে। আপনার আরও সুক্ষ্ম নিয়ন্ত্রণের প্রয়োজন হলে কিউএলবাউন্ড () বা কিউপারবাউন্ড () ব্যবহার করুন।

উদাহরণ:

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
দুর্ভাগ্যক্রমে এই অ্যালগরিদমটি এসটিএল ধারকগুলির সাথে সামঞ্জস্যপূর্ণ নয়।
বার্টোলো-ওট্রিট


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;
}

উদাহরণ: একটি অ্যারে বিবেচনা করুন, এ = [1,2,3,4,5,6,7,8,9] ধরুন আপনি প্রাথমিকভাবে 3 এর সূচকটি অনুসন্ধান করতে চান, শুরু = 0 এবং শেষ = 9-1 = 8 এখন , যেহেতু শুরু <= শেষ; মাঝামাঝি = 4; (অ্যারে [মাঝারি] যা 5)! = 3 এখন, 3 এর চেয়ে 5 টির চেয়ে ছোট হিসাবে মাঝের বামদিকে 3 টি রয়েছে Therefore সুতরাং, আমরা কেবল অ্যারের বাম অংশটি অনুসন্ধান করি, এখন, শুরু = 0 এবং শেষ = 3; মধ্য = ২ থেকে অ্যারে [মাঝারি] == 3, সুতরাং আমরা যে নম্বরটি অনুসন্ধান করছিলাম তা পেয়েছি। অতএব, আমরা এর সূচকটি মধ্যম সমান return


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;

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.