2015-07-18 6 views
8

Ich muss ständig Zahlen addieren zu einer vorsortierten Liste:Alternative zu Pythons .Sort() (für in eine große Liste einfügen und halten es sortiert)

for num in numberList: 
    list.append(num) 
    list.sort() 

Jede Iteration kurz ist, aber wenn die gegebene numberList enthält Zehntausende von Werten, die diese Methode verlangsamt. Gibt es eine effizientere Funktion, die eine Liste intakt lässt und herausfindet, welcher Index eine neue Zahl einfügen soll, um die richtige Reihenfolge der Zahlen zu erhalten? Alles, was ich versucht habe, selbst zu schreiben dauert länger als .sort()

+3

Warum versuchen Sie für jede Iteration zu sortieren? Das kannst du am Ende der for-Schleife tun, oder? ist das für den Zweck? – Viswesn

+0

Es gibt einen separaten Teil des Codes nach dem list.sort(), der einige Berechnungen ausführt, sodass das Sortieren der endgültigen Liste keine Option ist, sondern für jede Iteration. – user3555455

+0

Im Allgemeinen ist es eine gute Übung, Code in Python zu schreiben, um die Methoden in den Variablen außerhalb der Schleife zu binden, so dass der Interpreter die '.method 'nicht bei jeder Iteration der Schleife abrufen muss. – AMR

Antwort

9

Siehe die native bisect.insort(), die Insertion Sortierung auf Listen implementiert, sollte dies perfekt Ihre Bedürfnisse seit der complexity is O(n) at best and O(n^2) at worst anstelle von O (nlogn) mit Ihrem aktuelle Lösung (Umsortierung nach dem Einfügen).

Es gibt jedoch schnellere Alternativen zum Aufbau einer sortierten Datenstruktur wie Skip Lists und binäre Suchbäume, die eine Einfügung mit der Komplexität O (log n) bestenfalls und O (n) schlimmstenfalls oder sogar besser B- ermöglichen. Bäume, Red-Black trees, Splay-Bäume und AVL-Bäume, die alle eine Komplexität O (log n) sowohl im besten als auch im schlechtesten Fall aufweisen. Mehr Informationen über die Komplexität all dieser Lösungen und andere finden Sie in der großen BigO CheatSheet von Eric Rowell. Beachten Sie jedoch, dass bei all diesen Lösungen die Installation eines Drittanbietermoduls erforderlich ist und diese im Allgemeinen mit einem C-Compiler kompiliert werden müssen.

Es gibt jedoch ein reines Python-Modul namens sortedcontainers, das behauptet, so schnell oder schneller zu sein wie C kompilierte Python-Erweiterungen von Implementierungen von AVL-Bäumen und B-Bäumen (benchmark available here).

ich ein paar Lösungen gebenchmarkt zu sehen, welche die schnellste ist eine Insertionsort zu tun:

sortedcontainers: 0.0860911591881 
bisect: 0.665865982912 
skiplist: 1.49330501066 
sort_insert: 17.4167637739 

der Code, den ich zum Benchmark verwendet Ist hier:

from timeit import Timer 
setup = """ 
L = list(range(10000)) + list(range(10100, 30000)) 
from bisect import insort 

def sort_insert(L, x): 
    L.append(x) 
    L.sort() 

from lib.skiplist import SkipList 
L2 = SkipList(allowDups=1) 
for x in L: 
    L2.insert(x) 

from lib.sortedcontainers import SortedList 
L3 = SortedList(L) 
""" 

# Using sortedcontainers.SortedList() 
t_sortedcontainers = Timer("for i in xrange(10000, 10100): L3.add(i)", setup) 
# Using bisect.insort() 
t_bisect = Timer("for i in xrange(10000, 10100): insort(L, i)", setup) 
# Using a Skip List 
t_skiplist = Timer("for i in xrange(10000, 10100): L2.insert(i)", setup) 
# Using a standard list insert and then sorting 
t_sort_insert = Timer("for i in xrange(10000, 10100): sort_insert(L, i)", setup) 

# Timing the results 
print t_sortedcontainers.timeit(number=100) 
print t_bisect.timeit(number=100) 
print t_skiplist.timeit(number=100) 
print t_sort_insert.timeit(number=100) 

So zeigen die Ergebnisse, dass die sortedcontainers ist tatsächlich fast 7x schneller als halbiert (und ich erwarte, dass die Geschwindigkeitslücke mit der Listengröße zunimmt, da die Komplexität eine Größenordnung unterschiedlich ist).

Noch überraschender ist, dass die Skip-Liste langsamer als halbiert ist, aber es ist wahrscheinlich nicht so optimiert wie halbiert, die in C implementiert ist und einige Optimierungstricks verwenden kann (beachten Sie, dass das skiplist.py-Modul war) die schnellste Pure-Python-Skip-Liste, die ich finden konnte, die pyskip module ist viel langsamer).

Ebenfalls zu beachten: Wenn Sie komplexere Strukturen als Listen verwenden müssen, bietet das sortainedcontainers-Modul SortedList, SortedListWithKey, SortedDict und SortedSet an (während bisect nur auf Listen funktioniert). Vielleicht interessiert Sie auch diese somewhat related benchmark und diese complexity cheatsheet of various Python operations.

+1

"Komplexität ist O (log n)" - warum? O (log n) ist für das Finden der Stelle zu einfügen, aber zum Einfügen benötigen Sie noch O (n) –

+0

Einfügen in eine Python-Liste mit Halbierung scheint in konstanter Zeit O (1), also einmal der Index zum Einfügen von Sortierung getan werden gefunden wird, gibt es keine zusätzlichen Kosten – gaborous

+1

"Einfügen in eine Python-Liste mit Halbierung scheint in konstanter Zeit O (1) getan werden" - es ist unmöglich, Alter. Pythons Liste ist ein Array, keine verknüpfte Liste. –

17

können Sie die bisect.insort() function verwenden, um Werte in eine bereits sortierte Liste einzufügen:

from bisect import insort 

insort(list, num) 

Beachten Sie, dass dies noch einige Zeit dauern würde als die übrigen Elemente nach der Einfügemarke alle einen Schritt nach oben verschoben werden müssen, ; Vielleicht möchten Sie darüber nachdenken, die Liste stattdessen als verkettete Liste zu implementieren.

Wenn Sie jedoch die Liste sortiert halten, um immer die kleinste oder größte Nummer zu erhalten, sollten Sie statt dessen die heapq module verwenden; Ein Heap wird nicht in einer streng sortierten Reihenfolge gehalten, sondern ist sehr effizient, um Ihnen entweder den kleinsten oder den größten Wert zu jeder Zeit sehr schnell zu geben.

+3

Dies ist die Analyse der Leistungssteigerung. Run auf einer Liste von '100.000' zufällig generierten Integern.Time for insort 1.649233102798462' ' Zeit für list_append und list_sort 344.4988350868225' 'Zeit für list.append und list.sort 559.2065420150757' – AMR

+1

Was ist mit Bäumen? Es ist schon eine Weile her, seit ich sie gebraucht habe, aber bieten sie keine vernünftige Zeit für Zugriff, Einfügen und Löschen, selbst wenn sie sortiert sind? – jpmc26

+0

Ein binärer Suchbaum kann auch funktionieren, ja, abhängig von den Anwendungsfällen. –

Verwandte Themen