Autor |
Beitrag |
MarkusD
      
Beiträge: 22
|
Verfasst: Mi 18.07.07 11:59
Moin moin,
ich bin dabei, ein dynamisches Array (von nem Record) zu sortieren.
Genauer: Wenn ich ein Element im Array nicht mehr brauche, sortiere ich die anderen Elemente dahinter um eins zurück und "schneide" dann das letzte ab.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| for i:= 0 to High(Data) do begin if (Data[i].Destroy) then begin Data[i].Pc1.ReleaseMemory; Data[i].Pc2.ReleaseMemory; for j:= i to High(Data) - 1 do begin Data[j]:= Data[j + 1]; end; SetLength(Data, High(Data)); Application.ProcessMessages; end; end; |
Wenn ich nur wenige Elemente drinne habe, funktioniert alles soweit, habe ich jetzt aber viele drinne, was die Performance deutlich runter zieht (es handelt sich um Explosionen in einem 3d Spiel) bekomme ich eine Zugriffsverletzung.
Kann es vielleicht ein Problem sein 2 Elemente in einem Proceduredurchgang zu löschen? Das komische ist: Wenn ich pro gerenderten Frame immer eine Explosion, also ein Element adde, funktioniert alles wunderbar, wenn ich aber irgendwann aufhöre zu adden, und die Explosionen vorbei sind, und ich sie löschen will, kommt eine Zugriffsverletzung. Kann es vielleicht sein, dass ich dann zu oft Speicher freigeben/nehmen will, und ich dann einen Error bekomme?
Markus
|
|
wwwdirk
      
Beiträge: 38
D6 Prof / D2005 Prof
|
Verfasst: Mi 18.07.07 12:40
Pauschal würde ich anmerken, dass das eigentliche Array nicht verkürzt wird, sondern das letzte Element immer vermehrt wird.
Müsste es nicht so heissen?
Delphi-Quelltext 1:
| SetLength(Data, High(Data)-1); |
|
|
Dunkel
      
Beiträge: 682
Mac OS X Snow Leopard
Xcode 3.1
|
Verfasst: Mi 18.07.07 12:48
_________________ Ich streite einsam mich mit dieser Oberflächenwelt
Gutes sei ein löblich Brot von dem ich zehre - bis zum Tod [Das Ich - Im Ich]
|
|
ene
      
Beiträge: 779
Erhaltene Danke: 1
Vista, XP, W2K
Delphi, .Net, Deutsch und Englisch
|
Verfasst: Mi 18.07.07 12:51
Moin,
Wenn man Einträge eines Arrays löschen möchte, sollte man von hinten nach vorne laufen, denn sonst will man weiter laufen, als es überhaupt Einträge gibt.
_________________ Wir, die guten Willens sind, geführt von Ahnungslosen, Versuchen für die Undankbaren das Unmögliche zu vollbringen.
Wir haben soviel mit so wenig so lange versucht, daß wir jetzt qualifiziert sind, fast alles mit Nichts zu bewerkstelligen.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mi 18.07.07 12:53
Moin!
MarkusD hat folgendes geschrieben: | habe ich jetzt aber viele drinne, was die Performance deutlich runter zieht (es handelt sich um Explosionen in einem 3d Spiel) |
In diesem Fall würde ich von dynamischen Arrays abraten und statt dessen lieber eine lineare Liste nehmen, das ist sehr viel schneller. Oder alternativ nicht an der Liste rumbasteln, sondern nur den Eintrag NILen.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Stefan.Buchholtz
      
Beiträge: 612
WIN 2000, WIN XP, Mac OS X
D7 Enterprise, XCode, Eclipse, Ruby On Rails
|
Verfasst: Mi 18.07.07 12:55
Das Problem liegt daran, dass der Ausdruck für den Maximalwert einer for-Schleife nur einmal, vor dem ersten Schleifendurchlauf ausgewertet wird. In deinem Fall berücksichtigt also die äussere Schleife nicht, wenn sich die Grösse des Arrays in zwischendurch ändert. Du solltest die äußere Schleife als while-Schleile schreiben, dann wird die Abbruchbedingung auch dann richtig abgefragt, wenn sich die array-Grösse ändert.
Ist die Reihenfolge der Elemente wichtig? Wenn die Reihenfolge egal ist, ist es besonders bei einem großen Array wesentlich schneller, das zu löschende Element einfach mit dem letzten Element zu vertauschen und dann das Array zu verkleinern. Das spart die innere Schleife komplett.
Wenn sich die Anzahl der Array-Elemente häufig ändert, ist es am besten, sich die Anzahl in einer Variable zu merken und das Array beim Löschen von Elementen gar nicht zu verkleinern. Beim Hinzufügen von Elementen solltest du das Array in grossen Blöcken vergrößern statt immer nur um 1. Ich mache es normalerweise so, dass ich mit einer festen Startgröße, z.B. 16 anfange und die Array-Größe jedesmal verdoppele, wenn das Array zu klein wird. Jedes Vergrößern eines dynamischen Arrays bedeutet potentiell eine neue Speicherallokation und das Umkopieren des Arrays in den neuen Speicherblock - das wird ziemlich langsam, wenn das Array gross ist.
Stefan
_________________ Ein Computer ohne Windows ist wie eine Schokoladentorte ohne Senf.
|
|
MarkusD 
      
Beiträge: 22
|
Verfasst: Mi 18.07.07 13:05
Danke Stefan, das wars
Eigentlich dürfte das array nicht zu groß werden (max 20), größer nur zum testen.
Vielleicht "baue" ich es dann auch auf eine Liste um, bzw mache es so wie Stefan gesagt hat.
markus
|
|
|