Ich habe eine Reihe von Floats, die vom kleinsten zum größten sortiert sind, und muss in der Lage sein, den nächsten Float auszuwählen, der größer oder kleiner als ein übergebener Eingabewert ist. Dieser Eingabewert ist nicht unbedingt als Wert im Array vorhanden.
Ein naiver Ansatz wäre eine einfache lineare Suche durch das Array. Das könnte so aussehen:
void FindClosestFloatsInArray( float input, std::vector<float> array,
float *min_out, float *max_out )
{
assert( input >= array[0] && input < array[ array.size()-1 ] );
for( int i = 1; i < array.size(); i++ )
{
if ( array[i] >= input )
{
*min = array[i-1];
*max = array[i];
}
}
}
Aber wenn das Array größer wird, wird dies natürlich immer langsamer.
Hat jemand eine Idee zu einem Algorithmus, mit dem ich diese Daten optimaler finden kann? Ich habe bereits zu einer binären Suche gewechselt, die die Dinge etwas verbessert hat, aber sie ist immer noch viel langsamer als ich es gerne hätte, und da ich nicht nach einem bestimmten Wert suche, der im Array vorhanden ist, kann sie niemals beendet werden früh.
Weitere Informationen: Die Gleitkommawerte im Array sind nicht unbedingt gleichmäßig verteilt (dh das Array kann aus den Werten "1.f, 2.f, 3.f, 4.f, 100.f, 1200.f" bestehen 1203.f, 1400f.
Ich mache diesen Vorgang hunderttausend Mal, aber ich kann jede Menge Vorverarbeitung für das Array von Floats durchführen, wenn dies die Suchzeit verbessert. Ich kann mich absolut ändern, um etwas anderes als einen Vektor zum Speichern zu verwenden, wenn das hilft.
quelle
Antworten:
Der Code in der Frage (eine lineare Suche) wird, wie Sie zu Recht betonen, für große Float-Arrays langsam. Technisch gesehen ist es O (n), wobei n die Anzahl der Gleitkommawerte in Ihrem Array ist.
Im Allgemeinen ist das Beste, was Sie tun können, um einen Wert in einem geordneten Array zu finden, eine rekursive Baumsuche (z. B. eine binäre Suche). In diesem Fall können Sie eine O (log n) -Suchzeit für die Anzahl der Elemente erzielen in Ihrem Array. O (log n) ist für große Werte von n viel besser als O (n).
Mein vorgeschlagener Ansatz wäre daher eine einfache binäre Suche des Arrays , dh:
Dies ist ein O (log n) -Algorithmus, der für fast alle Situationen schnell genug sein sollte. Intuitiv halbiert es den zu durchsuchenden Bereich bei jedem Schritt, bis Sie den richtigen Wert gefunden haben.
Es ist wirklich schwer, die einfache binäre Suche zu testen. Wenn Sie dies also bereits korrekt implementiert haben, sind Sie möglicherweise bereits ziemlich nahe am Optimum. Wenn Sie jedoch die Verteilung der Daten kennen und / oder einen begrenzten Bereich von Suchwerten (x) haben, können Sie noch einige weitere fortgeschrittene Tricks ausprobieren:
Wenn Sie sich jedoch nicht in einer ganz besonderen Situation befinden, würde ich wahrscheinlich empfehlen, bei der einfachen binären Suche zu bleiben. Gründe dafür:
quelle
Das scheint einfach zu sein:
Führen Sie eine binäre Suche nach dem Float durch, den Sie binden möchten - O (log n) time.
Dann ist das Element links davon die Untergrenze und das Element rechts davon die Obergrenze.
quelle
Die offensichtliche Antwort ist, die Schwimmer in einem Baum zu speichern . Die Unterstützung von "vorherigen" und "nächsten" Operationen ist in einem Baum trivial. Machen Sie einfach ein "Weiter" für Ihren Wert und dann ein "Zurück" für den Wert, den Sie im ersten Schritt finden.
quelle
Dieses Papier ("sublogarithmische Suche ohne Multiplikationen") könnte von Interesse sein; Es enthält sogar Quellcode. Zu Vergleichszwecken können Sie eine Gleitkommazahl als Ganzzahl mit demselben Bitmuster behandeln. Dies war eines der Entwurfsziele des IEEE-Gleitkomma-Standards.
quelle