Was ist ein effizienter Weg, um einen großen Block von Elementen vom Anfang einer TList in Delphi zu löschen

8

Löschen (0) von einer TList ist teuer, weil alle nachfolgenden Elemente nach unten bewegt werden müssen. Wenn ich eine große Anzahl von Elementen am Anfang einer noch größeren Liste löschen muss, was ist der schnellste Weg?

    
rossmcm 01.12.2011, 22:12
quelle

6 Antworten

8

Das Löschen eines großen Bereichs von Elementen am Anfang von TList ist teuer. Obwohl der Klassenname schmeichelt, um zu täuschen, ist ein TList tatsächlich ein Array. In TList gibt es keine Möglichkeit, einen Bereich zu löschen - jeder Eintrag muss einzeln gelöscht werden, und dann wird der Rest der Liste nach unten verschoben. Für einen großen Bereich, der eine Menge Neuzuweisungen und vollständige Listenbewegungen provozieren wird.

Wenn Sie ein moderneres Delphi hätten, könnten Sie die generische Listenklasse TList<T> verwenden und nutzen Sie die Methode DeleteRange . Die Dokumentation enthält diese wichtige Anmerkung:

  

Dies ist eine O (ACount) -Operation.

In Delphi 2006 können Sie etwas mit äquivalenten Leistungsmerkmalen wie diesem schreiben:

%Vor%     
David Heffernan 01.12.2011, 22:39
quelle
4

Wie Marcelo bereits gesagt hat, könnten Sie den ganzen Block kopieren, aber anstatt dieses Element nach Element zu schreiben, können Sie das Ganze mit einem Aufruf zu Move () verschieben, indem Sie TList.List als Argument verwenden.

Beachten Sie, dass TList.List in älteren Delphi-Versionen ein PPointerList ( ^TPointerList; TPointerList = array[0..MaxListSize - 1] of Pointer; ) war und in Delphi XE2 zu TPointerList ( TPointerList = array of Pointer; ) wurde. Daher sollten Sie die korrekte Indirektion verwenden:

%Vor%

und

%Vor%     
PatrickvL 01.12.2011 22:50
quelle
2

So machen Sie das in XE2, denn TList ist ein Array von Zeigern.

Die Implementierung wird in Delphi 2006 ähnlich sein, aber ich kann den Code nicht schreiben, da ich 2006 nicht habe.

%Vor%

Solange all die Dinge, auf die die Zeiger zeigen, anderswo Speicher verwaltet werden, gibt es kein Leck.

Hier ist der Beweis:

%Vor%

Der Beweis weist große Speicherlecks auf, aber wir haben die Objekte nur zum Anzeigen der Werte erstellt.

    
Marcus Adams 02.12.2011 00:24
quelle
1

Wenn die Reihenfolge wichtig ist und Sie N Elemente an der Vorderseite entfernen müssen:

%Vor%

Ich habe diesen Code nicht wirklich gut durchdacht, also müssen Sie nach Fehlern und ähnlichem suchen.

Wenn Reihenfolge nicht wichtig ist, können Sie einfach die letzten N Elemente mit den ersten N Elementen austauschen und die letzten N Elemente wie oben löschen.

    
Marcelo Cantos 01.12.2011 22:26
quelle
1

Hier ist ein Gedanke: Wenn Sie wissen, dass alle Elemente in Ihrer Liste zugewiesen sind, können Sie die zu entfernenden Elemente löschen und einfach TList.Pack () aufrufen, um herauszufinden, wo sich die leeren Stellen befinden und alles andere beiseite zu schieben effizient wie möglich. Dies erfordert jedoch einen Scan durch alle Elemente, also ist es möglicherweise nicht das, was Sie wollen, aber es verwendet auch nicht Löschen (und verhindert somit Notofy-Aufrufe). Die Implementierung von Pack hat sich zwischen D2006 und XE2 nicht ein wenig geändert, so dass Sie sich auf die Effizienz verlassen können.

Beachten Sie, dass Sie, um die Elemente zu entfernen, die Sie entfernen möchten, List[aIndex] := nil verwenden könnten, aber dies würde immer noch einen Notify () -Aufruf erzwingen, also könnte List.List[aIndex] := nil dafür schneller sein.

    
PatrickvL 02.12.2011 08:23
quelle
0

Verwenden Sie zunächst BeginUpdate und EndUpdate, um zu verhindern, dass die Benutzeroberfläche der TList aktualisiert wird, indem Sie jedes Element löschen.

Sekunde: Versuchen Sie, zuerst die Elemente an der untersten Stelle in der Liste zu löschen. Mit anderen Worten, das Löschen von Elementen von oben nach unten nimmt die Liste bei anderen Elementen weniger effizient.

    
Galaxydreams 01.12.2011 22:18
quelle

Tags und Links