webentwicklung-frage-antwort-db.com.de

Wo bekomme ich einen "nützlichen" C++ - Binärsuchalgorithmus?

Ich brauche einen binären Suchalgorithmus, der mit den C++ - STL-Containern kompatibel ist, etwa std::binary_search im <algorithm>-Header der Standardbibliothek, aber ich brauche ihn, um den Iterator zurückzugeben, der auf das Ergebnis zeigt, und nicht auf einen einfachen Booleschen Hinweis, ob das Element existiert.

(Nebenbei bemerkt, was zum Teufel dachte das Standardkomitee, als es die API für binary_search definierte ?!)

Meine Hauptsorge ist hier, dass ich die Geschwindigkeit einer binären Suche benötige. Obwohl ich die Daten mit anderen Algorithmen finden kann, wie unten erwähnt, möchte ich die Tatsache nutzen, dass meine Daten sortiert sind, um die Vorteile einer Binärdatei zu erhalten Suche, keine lineare Suche.

bisher schlagen lower_bound und upper_bound fehl, wenn das Datum fehlt:

//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

Hinweis: Ich benutze auch einen Algorithmus, der nicht zum std-Namespace gehört, solange er mit Containern kompatibel ist. Zum Beispiel boost::binary_search.

91
Robert Gould

Es gibt keine solchen Funktionen, aber Sie können eine einfache mit std::lower_bound , std::upper_bound oder std::equal_range schreiben.

Eine einfache Implementierung könnte sein

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
}

Eine andere Lösung wäre die Verwendung eines std::set, der die Anordnung der Elemente garantiert und eine Methode iterator find(T key) bereitstellt, die einen Iterator an den angegebenen Artikel zurückgibt. Ihre Anforderungen sind jedoch möglicherweise nicht mit der Verwendung eines Sets kompatibel (wenn Sie beispielsweise dasselbe Element mehrmals speichern müssen).

83
Luc Touraille

Sie sollten sich std::equal_range ansehen. Es werden zwei Iteratoren auf den Bereich aller Ergebnisse zurückgesetzt.

8
Luc Hermitte

Es gibt eine Reihe von ihnen:

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

Suchen nach:

Auf einer separaten Notiz:

Sie dachten wahrscheinlich, dass das Durchsuchen von Containern mehr als ein Ergebnis liefern könnte. In den seltenen Fällen, in denen Sie nur auf Existenz prüfen müssen, wäre eine optimierte Version auch Nizza.

6
Martin York

Wenn std :: lower_bound für Ihren Geschmack zu niedrig ist, möchten Sie vielleicht boost :: container :: flat_multiset ..__ prüfen, da dies ein Drop-In-Ersatz für std :: multiset ist, das als sortiert implementiert ist Vektor mit binärer Suche.

3
ZunTzu

std :: lower_bound () :)

1
moogs

Überprüfen Sie diese Funktion, qBinaryFind :

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

Führt eine binäre Suche des Bereichs durch [begin, end) und gibt die Position zurück eines Wertevorkommens. Wenn dort sind keine Vorkommen des Werts, gibt .__ zurück. Ende.

Die Elemente im Bereich [Anfang, Ende) muss aufsteigend sortiert sein; sehen qSortieren ().

Wenn es viele Vorkommen von .__ gibt. denselben Wert, könnte einer von ihnen .__ sein. ist zurückgekommen. Verwenden Sie qLowerBound () oder qUpperBound (), wenn Sie feinere Steuerung.

Beispiel:

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)

Die Funktion ist im <QtAlgorithms>-Header enthalten, der Teil der Qt -Bibliothek ist.

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

Beispiel: Betrachten Sie ein Array, A = [1,2,3,4,5,6,7,8,9] Angenommen, Sie möchten den Index von 3 .__ durchsuchen. Anfangs beginnen Sie mit 0 und end = 9-1 = 8 __. Nun, da start <= end; mittel = 4; (array [mid], was 5 ist)! = 3 Nun liegt 3 links von der Mitte, da es kleiner als 5. Daher suchen wir nur den linken Teil des Arrays Starten Sie also = 0 und end = 3; mid = 2.Since array [mid] == 3, daher haben wir die gesuchte Zahl gefunden. Daher geben wir seinen Index zurück, der gleich mid ist.

Die kürzeste Implementierung, die sich wundert, warum sie nicht in der Standardbibliothek enthalten ist:

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

Von https://en.cppreference.com/w/cpp/algorithm/lower_bound

0
trozen

Eine Lösung, die die Position innerhalb des Bereichs zurückgibt, könnte wie folgt aussehen und nur Operationen für Iteratoren verwenden (sollte auch funktionieren, wenn der Iterator nicht arithmetisch ist):

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)/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;

}
0
Michele Belotti