2010-04-07 16 views
8

sagen wir, ich habe eine sortierte Liste von Floats. Jetzt möchte ich den Index des nächstniedrigeren Artikels eines gegebenen Wertes erhalten. Der übliche For-Loop-Ansatz hat eine Komplexität von O (n). Da die Liste sortiert ist, muss es möglich sein, den Index mit O (log n) zu erhalten.Finden Sie das nächste untere Element in einer sortierten Liste

My O (n) Ansatz:

index=0 
for i,value in enumerate(mylist): 
    if value>compareValue: 
     index=i-1 

Gibt es einen Datentyp für dieses Problem in O Lösung (log n)?

freundlichen Grüßen Sebastian

+1

Binary Search: http://en.wikipedia.org/wiki/Binary_search_algorithm –

Antwort

10

Sie können auf einem Array/Liste eine binäre Suche tun, den Index des Objekts zu erhalten, die Sie suchen und den Index darunter erhalten den unteren Eintrag zu bekommen (vorausgesetzt, dass es ist eigentlich ein niedriger Eintrag!).

Siehe: Binary search (bisection) in Python

Vorsicht beim comparing floating point numbers für Gleichheit!

1

Um einen Teil der Frage zu Datentypen zu beantworten: In einem allgemeinen Sinn ist der Datentyp, der am besten geeignet ist, Dinge in O (log n) -Zeit zu finden (während O (1) bei Einfügungen und Löschungen erhalten bleibt!) . Sie können Dinge darin finden, indem Sie eine Reihe von Links-Rechts-Entscheidungen treffen, was sehr analog zu einer binären Suche in einer linearen Liste ist, aber (IMO) etwas konzeptuell intuitiver ist.

Das heißt, von dem, was ich von Python weiß, scheinen Binärbäume nicht in der Standardbibliothek der Sprache zu sein. Für Ihre Anwendung würde es wahrscheinlich keinen Vorteil geben, eine Implementierung nur für diesen Zweck zu integrieren.

Schließlich können Sie in einer sortierten Liste sowohl die Binärbäume als auch die Binärsuche verwenden, um die Suche um einen Schritt zu verkürzen: Es ist nicht notwendig, nach dem Schlüsselelement zu suchen und dann zu seinem Vorgänger zurückzukehren. Verwenden Sie stattdessen bei jedem Vergleichsschritt so, als ob der Schlüsselwert zu groß wäre. Dies führt dazu, dass Ihre Suche auf dem nächstkleineren Wert endet. Sorgfältig ausgeführt, kann dies auch bei dem von Bart angesprochenen "fast equal floating point value" Problem helfen.

15

Wie wäre es mit bisect?

>>> import bisect 
>>> float_list = [1.0, 1.3, 2.3, 4.5] 
>>> i = bisect.bisect_left(float_list, 2.5) 
>>> index = i - 1 
>>> index 
2 

Sie müssen möglicherweise den Fall eines Suchwert kleiner oder gleich dem niedrigsten/Wert ganz links in der Liste Griff separat (index == -1 in diesem Fall).

Je nachdem, welchen Index Sie bei Gleichheit haben möchten, müssen Sie stattdessen bisect_right verwenden.

+0

Ich denke, das funktioniert nicht: '>>> float_list = [0, 0,5, 1, 1.5, 2, 2.5, 3] // >>> float_list [bisect.bisect_left (float_list, 2.1)] // 2.5' Der nächste untere Punkt ist 2 – paul

+0

@paul: "funktioniert nicht" scheint eine Übertreibung zu sein zu mir :), aber ich habe die Antwort geklärt. Sie müssen -1 subtrahieren, um den Index zu erhalten. – stephan

2

Verwenden Sie das Modul bisect. Die Funktion

gibt den richtigen Einfügepunkt für das Element in der Liste zurück, um die sortierte Reihenfolge beizubehalten.

2
import bisect 

def next_lower_value(values_list, input_value): 
    index= bisect.bisect_left(values_list, input_value) 
    if index == 0: # there's not a "next lower value" 
     raise NotImplementedError # you must decide what to do here 
    else: 
     return values_list[index - 1] 

>>> l= [11, 15, 23, 28, 45, 63, 94] 
>>> next_lower_value(l, 64) 
63 
>>> next_lower_value(l, 63) 
45 
>>> next_lower_value(l, 1000) 
94 
>>> next_lower_value(l, 1) 
Traceback (most recent call last): 
    File "<pyshell#29>", line 1, in <module> 
    next_lower_value(l, 1) 
    File "<pyshell#26>", line 4, in next_lower_value 
    raise NotImplementedError # you must decide what to do here 
NotImplementedError 

Da Sie den Index und nicht den nächstniedrigeren Wert verlangen, ändern Sie die Funktion next_lower_valueindex - 1 statt values_list[index - 1] zurückzukehren.

1

Wenn ich dieses Recht lese, ist das nächst niedrigere Element das erste Element in der Liste, das kleiner oder gleich x ist. Die bisect documentation for searching sorted lists gibt diese Funktion:

def find_le(a, x): 
    'Find rightmost value less than or equal to x' 
    i = bisect_right(a, x) 
    if i: 
     return a[i-1] 
    raise ValueError 
Verwandte Themen