Autor |
Beitrag |
Flamefire
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 26.10.10 18:12
Ich möchte Objekte sortieren, deren Compare() Routine recht teuer ist.
Darum soll es demzufolge eine Sortiermethode sein, die mit so wenig wie möglich vergleichen auskommt und sonst auch möglichst schnell ist.
Die Anzahl der Elemente ist zwischen 2-6 typischerweise aber 3.
Die Sortierung wird jedoch extrem oft gemacht, da sich ALLE Objekt häufig ändern und danach sortiert werden müssen (dazwischen umsortieren ist nicht möglich)
Welche Variante kann ich nehmen?
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 26.10.10 18:23
Kannst du näheres über die Beschaffenheit der Objekte verraten? Warum ist die Compare()-Methode so teuer?
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 26.10.10 18:23
Bei drei Elementen ist das komplett wurscht, man braucht auf jeden Fall drei Vergleiche. Da kann man auch "Selectionsort" nehmen: Zuerst das Minimum suchen (2 Vergleiche), dann die beiden übrigen. Bei den anderen (4-6 Elemente) würde ich es mal mit Shakersort probieren, also ein Bubblesort der nicht immer in eine Richtung bubbelt, sondern abwechselnd von vorne nach hinten und zurück.
Ansonsten würde ich da einfach mal experimentieren, ob sich Quicksort, Mergesort oder Heapsort lohnt. 
_________________ We are, we were and will not be.
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 26.10.10 18:27
Naja, wenn er sehr häufig sortiert und sich ein Element ändern, kann man davon ausgehen, dass die anderen Elemente bereits sortiert sind. Das heißt für den ersten Sortiervorgang braucht man eine gewisse Anzahl Vergleiche, danach gibt es Potenzial für Optimierungen. Bei drei Elementen wären das dann zum Beispiel ein Vergleich im Best- und zwei Vergleiche im Worstcase.
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Di 26.10.10 18:36
Klingt für mich auch nach Insertionsort: nur beim Einfügen/Ändern kontrollieren wohin damit, ansonsten gar nichts weiter tun.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 26.10.10 19:01
Wird vermutlich wirklich Insertionsort.
Ok danke.
Geändert werden immer erst ALLE Elemente und dann wird sortiert.
Die CompareMethode vergleicht intern einige weitere Daten, darum ist die recht teuer.
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 26.10.10 19:13
Wenn sich jedes mal alle Elemente ändern, solltest du dir vielleicht doch mal Quicksort (oder Insertionsort in Kombination mit Binärsuche) angucken, um die Anzahl der Vergleiche zu reduzieren. Eventuell lohnt sich auch eine Fallunterscheidung, da wenn du wirklich sehr häufig nur drei Elemente sortieren musst, ein "direktes" Sortieren am schnellsten ist.
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 26.10.10 19:22
Für optimales Sortieren von Daten einer festen Länge lautet das Stichwort Sorting Network:
Zitat: | For 1 to 8 inputs optimal sorting networks are known. They have respectively 0, 1, 3, 5, 9, 12, 16 and 19 comparators (Knuth, 1997). The optimal depths for up to 10 inputs are known and they are respectively 0, 1, 3, 3, 5, 5, 6, 6, 7, 7. |
Da bist du ja gerade noch im Intervall  .
_________________ >λ=
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 26.10.10 19:27
Das ist etwa das was ich mit "direktem" Sortieren meinte. Sieht nur als Code net so schön aus 
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 26.10.10 19:36
Nur habe ich keine feste Länge...
Es gibt min. 2 und max. 7 Objekte. Und für jede Anzahl nen eigenen Algo?
Achso noch schlimmer: Ich muss auch gleiche Werte erkennen können...
Es geht um eine Platzierung. Und da kanns halt sein, dass 2 den 2. Platz haben.
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 26.10.10 19:43
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 26.10.10 19:50
Jein...
Hab ein 1D Array und dann ein record als Eintrag: Objekt und ein Flag, ob es gleich dem darüber ist.
|
|
FinnO
      
Beiträge: 1331
Erhaltene Danke: 123
Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
|
Verfasst: Di 26.10.10 20:22
Moin,
kannst du vielleicht aus den Eigenschaften des Objekts eine "Punktzahl" errechnen? Die könnte man dann ja recht flott vergleichen..
LG
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 26.10.10 20:29
Hab ich auch schon überlegt. Und mir fällt gerade was sehr gutes dazu ein
Ein paar Bits schubsen und schon hab ich ne checksumme, die ich vergleichen kann
Obwohl...Bringt zwar im Fall größerer Mengen etwas, aber im Normalfall dürfte das langsamer sein...
Weil die Compare Methode ist so optimiert, dass nur verglichen wird, was nötig ist (early-out)
Bei ner Checksumm müsste ich trotzdem über alles drüber, dann noch einige Umwandlungen, Shifts und OR-Verknüpfungen...
Kommt auf nen Test an...
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 26.10.10 20:35
Flamefire hat folgendes geschrieben : | Achso noch schlimmer: Ich muss auch gleiche Werte erkennen können... |
Das sollte in jeden Algorithmus, auch in ein optimales Searching Network, ohne Mehraufwand einbaubar sein, indem du die Vergleichsergebnisse mitspeicherst und daraus ganz am Ende Gleichplatzierungen ableitest. Denn bei jedem vergleichsbasierten Algorithmus müssen ja Elementpaare, die am Schluss nebeneinander liegen, einmal verglichen worden sein.
_________________ >λ=
|
|
Dude566
      
Beiträge: 1592
Erhaltene Danke: 79
W8, W7 (Chrome, FF, IE)
Delphi XE2 Pro, Eclipse Juno, VS2012
|
Verfasst: Di 26.10.10 21:35
Wie oft sollen denn die Objekte neu sortiert werden, denn bei maximal 7 Objekten kann ich mir nicht vorstellen, dass es einen solchen Zeitaufwand kostet und man extra optimieren muss?
_________________ Es gibt 10 Gruppen von Menschen: diejenigen, die das Binärsystem verstehen, und die anderen.
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 26.10.10 21:54
Je Durchlauf so ca. 1-2 Mio mal...
Darum habe ich jeden Einzelschritt so weit wie möglich optimiert ohne das OOP ganz zu verhaun...
Variante jetzt sieht so aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| SetLength(places,plct); with places[0] do begin Object:=FMyObject[0]; index:=0; EqualToBelow:=false; end; for i := 1 to plct - 1 do begin inserted:=false; j:=0; while(j<i) do begin win:=places[j].Object.Compare(FMyObject[i]); if(win<0) then begin Move(places[j],places[j+1],sizeOf(places[0])*(i-j)); with places[j] do begin Object:=FMyObject[i]; index:=i; places[j].EqualToBelow:=false; end; inserted:=true; break; end else if(win=0) then begin ct:=i-j-1; if(ct>0) then Move(places[j+1],places[j+2],sizeOf(places[0])*ct); with places[j+1] do begin Object:=FMyObject[i]; index:=i; EqualToBelow:=places[j].EqualToBelow; end; places[j].EqualToBelow:=true; inserted:=true; break; end else while(j<i) and (places[j].EqualToBelow) do Inc(j); Inc(j); end; if(not inserted) then begin with places[i] do begin Object:=FMyObject[i]; index:=i; EqualToBelow:=false; end; end; end; ct:=0; for i := 0 to Length(places) - 1 do begin Inc(FScores[places[i].index*plct+ct]); if(not places[i].EqualToBelow) then Inc(ct); end; SetLength(places,0); |
Wie kann ich das noch weiter optimieren?
|
|