2014-03-25 7 views
7

Ich möchte die Anzahl der Einträge zwischen zwei Iteratoren einer std::multimap in weniger als O (N) Zeit zählen. Gibt es Tricks oder clevere Möglichkeiten, dies zu tun?Anzahl der Einträge zwischen zwei std :: multimap Iteratoren effizient zählen

Seit std::multimap bidirektionale Iteratoren hat, ist mein Verständnis, dass etwas wie std::distance dies in O (N) Zeit tun könnte.

Zusätzliche Details: Der Schlüssel multimap ist ein N-Tupel. Ich versuche die Anzahl der Einträge in der multimap zu finden, deren erstes Element des Schlüssels 0 ist. Die Optionen für das erste Element des Schlüssels sind 0 und 1, und die multimap verwendet eine strenge schwache Reihenfolge, in der das erste Element des Schlüssels ist immer das Wichtigste. h. alle Elemente mit 0 kommen vor allen Elementen mit 1.

Kontext: Die Iteratoren werden von equal_range zurückgegeben, die in logarithmischer Zeit läuft. Deklarativ möchte ich die Länge des Bereichs messen.

Vielen Dank.

+0

Ist ein Zähler nicht in Frage? – imreal

+0

Es ist nicht, aber ich würde es vorziehen, einen Zähler nicht manuell zu verwalten, wenn es eine andere Möglichkeit gibt, dies zu tun, die in STL integriert ist oder die keinen separaten Zähler benötigt. – Zach

+0

Es hat mich immer verärgert, dass Map/Set keinen Zugriff auf Tree-Travel-Bits bieten, die so etwas tun könnten. Auch 'std :: lower_bound (map_iter, map_iter, V)' ist aus dem gleichen Grund ineffizient. –

Antwort

5

Was Sie suchen genannte so wird heterogeneous comparison lookup, die in N3465 vorgeschlagen wurde.Es ermöglicht eine verschiedene, aber kompatible Vergleichsfunktion in der equal_range Mitgliedsfunktion, die verwendet wird, um die Key zu speichern. In Ihrem Fall wäre der Suchvergleichsoperator (erstes Tupelelement) anders als, aber konsistent mit dem tupellexikalischen Vergleich.

Leider wurde nur ein kleiner Teil dieses Papiers gemäß this Q&A in den Entwurf C++ 14 Standard aufgenommen. Der Autor des N3465-Papiers ist jedoch auch der Autor von Boost.MultiIndex, der this feature implementiert hat. Sie können emulate a std::multimap durch Befolgen der Boost.MultiIndex-Dokumentation.

Sobald Sie die verallgemeinerte equal_range Elementfunktion eines angepassten boost::multiindex_container verwendet haben, können Sie einfach std::distance() für die zurückgegebenen Iteratoren tun. Die Komplexität wäre logarithmisch in der Containergröße für den equal_range und linear in der Größe des zurückgegebenen Iteratorbereichs. Wenn Sie nicht an dem Ergebnis, sondern nur an der Zählung interessiert sind, gibt es auch eine verallgemeinerte count() Elementfunktion, die diese in derselben logarithmischen + linearen Zeit zurückgibt.

+0

Interessant, dass die Boost-Bibliothek den 'std :: multimap'-Container mit dem' boost :: multiindex_container' verbessert. –

+0

@CPlusPlusOOAandD Boost war in der Vergangenheit der Ort, an dem viele der aktuellen Standardbibliotheksfunktionen implementiert und für eine ernsthafte Nutzung getestet wurden (Smartpointer, Hashtabellen usw.). Daher ist die Anleitung von z.B. Bücher als effektives C++, um sich mit Boost vertraut zu machen. BTW, nettes Zitat von N3465: "Der Autor hat einige Berichte erhalten, die auf diese Funktionalität als Grund zeigen, um Boost.MultiIndex anstelle der Standard-assoziativen Behälter zu verwenden" – TemplateRex

+0

Ich bin sehr bewusst von der Boost-Teststrecke für neue Standardbibliothekseigenschaften . Es ist ein wenig überraschend, dass der MultiIndex-Container bereits nicht Teil des Standards ist (z. B. verfügbar seit Boost 1.32.0). Meine 2001-Kopie von Effective C++ scheint sehr wenig Boost-Material zu haben. Irgendwelche Empfehlungen neben dieser Seite: [Wo finde ich eine gute Boost-Referenz? - geschlossen] (http://stackoverflow.com/questions/1126118/where-can-i-find-a-good-boost-reference/1126210#1126210) auf Boost Nachschlagewerke? Ich erhalte derzeit die Website-Dokumentation mit 'wget'. –

0

Sie möchten die std::distance-Methode aus der Iterator-Bibliothek verwenden. Die Referenz ist std::distance. Hier ist die Hauptreferenz: Iterator library.

Die Beschreibung lautet also ab 25. März 2014:

template< class InputIt > 
typename std::iterator_traits<InputIt>::difference_type 
    distance(InputIt first, InputIt last); 

Gibt die Anzahl der Elemente zwischen dem ersten und letzten.

Das Verhalten ist undefiniert, wenn last nicht von vornherein erreichbar ist, indem es (möglicherweise) wiederholt inkrementiert wird.

Parameter
erste - Iterator auf das erste Element zeigt
zuletzt - Iterator auf das letzte Element zeigt

Typ Anforderungen
- InputIt müssen den Anforderungen der InputIterator erfüllen. Der Betrieb ist effizienter wenn InputIt erfüllt zusätzlich die Anforderungen der RandomAccessIterator

Rückgabewert
Die Anzahl der Elemente zwischen dem ersten und letzten.

Komplexität
Linear.
Wenn jedoch InputIt zusätzlich die Anforderungen von RandomAccessIterator erfüllt, ist die Komplexität konstant.


Beachten Sie, dass sich die oben genannten Angaben ändern können. Die genauesten Informationen erhalten Sie, indem Sie direkt zur Referenzseite std::distance navigieren.

Beispielcode aus der std::distance Referenz Webseite:

include <iostream> 
#include <iterator> 
#include <vector> 

int main() 
{ 
    std::vector<int> v{ 3, 1, 4 }; 

    auto distance = std::distance(v.begin(), v.end()); 

    std::cout << distance << '\n'; 
} 
+1

Distanz ist hier O (n), damit hilft das OP nicht. –

+0

Sollte konstante Zeit sein, oder? –

+0

RandomAccessIterator erfüllt die Anforderungen von BidirectionalIterator, aber nicht umgekehrt. http://en.cppreference.com/w/cpp/iterator – Zach

Verwandte Themen