BPS #2: Wörter sortieren - Auswertung
Übersicht

![]() |
XeresModeratorBetreff: BPS #2: Wörter sortieren - Auswertung |
![]() Antworten mit Zitat ![]() |
---|---|---|
So, die Zeit ist 'rum!
Das war die Aufgabe Postet hier eure Ergebnisse, Codes, Gedanken. Lernt von den anderen, seht euch deren Quelltext an und versucht euren eigenen zu verbessern. Diskussion Postet zu euren Codes stets eine kurze Erklärung mit euren Gedanken in denen ihr simpel gesagt die Frage "Wieso habe ich XY auf diese Art gelöst?" beantwortet. Beiträge, die nur den Code enthalten werden wir aus dem Thread entfernen. Nächste Aufgabe In drei Tagen am Sonntag dem 13. wird die Musterlösung nach editiert und die nächste Aufgabe eingestellt. Viel Spaß & viel Erfolg! Musterlösung: Lösung 1: BlitzMax: [AUSKLAPPEN] SuperStrict Lösung 2 (mit Compare-Funktion): BlitzMax: [AUSKLAPPEN] SuperStrict |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
- Zuletzt bearbeitet von Xeres am So, Feb 13, 2011 19:08, insgesamt einmal bearbeitet
![]() |
BlitzMoritz |
![]() Antworten mit Zitat ![]() |
---|---|---|
Tut mir leid - ich habe mir ein bisschen Zeit gegönnt - das Problem war schlichtweg zu spannend!
Darum bin ich jetzt so frei und erlaube mir, meine vier ganz unterschiedlichen Verfahren vorzustellen. Vorab möchte ich noch kurz auf die Funktion "Wortliste_erstellen()" hinweisen, mit der eine Liste von beliebig vielen Worten aus einem vorgegebenen Alphabet zufällig erstellt wird. Diese "Worte" sind natürlich keine echten Worte mit Sinn, sondern rein zufällige Aneinanderreihungen von Buchstaben. Zweck der Funktion ist, die verschiedenen Sortierverfahren in hoher Anzahl und tatsächlich beliebiger Buchstabenkombination testen zu können, ohne dem Risiko ausgesetzt zu sein, durch ein paar wenige willkürlich festgelegte Beispielworte die Schnelligkeit und die Richtigkeit der Sortieralgorithmen nicht wirklich zu überprüfen. Nun zu meinem ersten Verfahren: Ich postete bereits, dass BlitzMax selbst mit der Klasse TList und ihrer Methode "SortList()" ein Verfahren zum Sortieren von Strings zur Verfügung stellt, welches allerdings für sich allein unseren deutsch-sprachigen Sortieransprüchen leider nicht genügt: Sämtliche Großbuchstaben werden a priori VOR alle Kleinbuchstaben eingeordnet: Es wird also "Zebra" VOR "aber" eingeordnet, was falsch ist. Auch die zahlreichen Sonderbuchstaben kommen gemäß ASCII-Nummern ganz hinten "nachgetröpfelt". Die Methode muss also ein bisschen modifiziert bzw. korrigiert werden, was auch ohne größeren Aufwand gelingt. Das dafür angewandte System ist denkbar einfach: Man nehme jedes Originalwort mit potentiellen Umlauten etc. und formatiere es so, dass es von SortList() korrekt sortiert wird. Formatieren bedeutet hier, alle Großbuchstaben in Kleinbuchstaben und die Sonderzeichen in einen (siehe unten) alphabetisch irgendwie logischen Ersatz zu verwandeln. Damit das unverfälschte Originalwort aber erhalten bleibt, hängt man es einfach, durch einen Trennstrich isoliert, an das formatierte Wort an und lässt per SortList() dieses "Doppelwort" sortieren. Für das Ergebnis schneidet man sich hernach nur noch das hintere Originalwort heraus. Vorraussetzung für das Gelingen ist natürlich, dass das hierfür benutzte Trennzeichen in keinem der Originalwörtern vorkommen darf. Normalerweise sollte so etwas wie "|" keine Probleme machen. Will man jedoch aus irgendwelchen Gründen ein anderes verwenden, kann man es einfach im zweiten optionalen Funktionsparameter der Sortier-Funktion definieren: BlitzMax: [AUSKLAPPEN] Const Wortanzahl% = 2000 Nun hieß es ja, man solle sich seine eigene Gedanken machen, wie vorzugehen sei, ohne "SortList()" zu verwenden. Schließlich kommen ja unsere armen BlitzBasic-Freunde auch gar nicht in den Genuss dieses 'Service'. ![]() Basis aller meiner drei folgenden Verfahren ist ein konstanter Alphabet-String, der nicht nur den zur Verfügung stehenden Buchstaben-Vorrat darstellt, sondern durch seine Anordnung auch die gewünschte alphabetische Hierarchie, und der je nach Wunsch und Sprache individuell angepasst werden kann. Darauf aufbauend erstellte ich den globalen Array "Platz_im_Alphabet[]", mit dem ich später, ausgehend von der definierten Alphabet-Hierarchie, schneller entscheiden konnte, welcher Buchstabe gegen einen anderen "siegt". Weiterhin habe ich die Entscheidung, ob ein Wort alphabetisch vor dem anderen steht, also die Aufgabe, zwei Worte alphabetisch zu vergleichen, in einer Funktion mit dem Namen "Worte_vergleichen()" isoliert. Für die Sortierfunktion selbst ist mir zunächst eine ganz einfache Idee eingefallen, deren Simplizität beinahe "lustig" wirkt, weil ich mich selbst um ein alphabetisches Einordnen gar nicht ernsthaft bemühe: Ich lasse lediglich jedes der Worte wie in einem großen Sportturnier genau einmal gegen jedes der anderen Worte "spielen" und notiere mir den Gewinner. Je häufiger ein Wort "gewonnen" hat, desto weiter vorne steht es im Alphabet. Am Ende weise ich jedem Wort direkt über seine Gewinnerpunktzahl die entsprechende Stelle in einem Array zu. Einen kleinen Haken hat die Sache aber doch noch: Was ist bei einem "Remis", wenn zwei Worte identisch sind? Vergäbe man dabei keine Punkte, bestünde die Gefahr, dass nicht alle Listen-Plätze vergeben sind, da mehrere Worte die gleiche Anzahl von SiegerPunkten besäßen. Dem kann man vorbeugen, indem man auch bei einem "Unentschieden" einen Punkt vergibt, und zwar stets nach dem gleichen System: Spielt in der Reihenfolge ein Wort gegen ein zweites Wort "Remis", so erhält per Definition das erste Wort den Gewinnerpunkt, basta. Dieses Verfahren arbeitet tadelos, hat aber den Nachteil, dass es leider nicht besonders schnell ist, man kann den Aufwand leicht ausrechnen: Bei 10 Wörtern spielt das erste neunmal gegen die anderen, das zweite (das schon gegen das erste gespielt hat) spielt achtmal gegen die übrigen usw. Am Ende erhält man 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 45 Es gleicht dem bekannten "Händeschütteln-Problem", allgemein sind es bei n Worten n * (n-1) / 2 Vergleiche. Der Rechenaufwand, jedem mit jedem zu vergleichen, benötigt bei 10.000 Wörtern 49.995.000 (also fast 50 Millionen) Wortvergleiche, auf meinem Rechner dauerte dieser Vorgang über 13 Sekunden. BlitzMax: [AUSKLAPPEN] Const Wortanzahl% = 2000 Bei meinem dritten Verfahren versuchte ich, effektiver zu sortieren und v.a. zu vermeiden, dass tatsächlich jedes Wort wie beim vorigen Verfahren gegen jedes andere antreten muss. Denn wenn man schon einen Teil der Wörter richtig sortiert hat, genügt es doch, für das noch unsortierte Wort lediglich die richtigen Stelle für das Einordnen zu finden. Diese Stelle könnte ja eventuell ganz in der Nähe der ursprünglichen Wortposition liegen. Mit der Laufvariablen w läuft meine dritte Sortiert-Funktion also Wort für Wort durch das Wort-Array. Und falls sie (mit der Worte_vergleichen()-Funktion) auf ein unpassendes neues Wort trifft, läuft dieses mit einer zweiten Laufvariabeln in der bereits sortierten Teilliste wieder so weit zurück, bis es an der richtigen Stelle einrastet: BlitzMax: [AUSKLAPPEN] Const Wortanzahl% = 2000 Erweist sich mein drittes Sortierverfahren schon mehr als doppel so schnell wie das zweite, so ist die Geschwindigkeit gegenüber der modifizierten SortList()-Methode leider immer noch enttäuschend langsam: Für 10.000 Wörter benötigte mein Rechner gut sechs Sekunden. Darum hat mich noch einmal der Ehrgeiz gepackt, ein wirklich schnelleres Sortierverfahren zu finden. Da ich vermutete, dass der Geschwindigkeitsverlust meiner vorigen Methode mitunter darin begründet ist, dass ich ein ums andere Mal, immer und immer wieder einzelne Wörter Schritt für Schritt die ganze Wortliste nach oben und unten umsortiere, bis sie endlich einrasten, fragte ich mich: Wie kann man dieses elende Umschichten generell vermeiden? Meine viertes Verfahren hat daher einen ganz anderen Ansatz: Statt die Bücher auf einem einzigen riesigen Stapel hin- und herzuschichten, verteile ich sie einfach von vorneherein in ein großes Regal aus vielen separat nummerierten Schubfächern, die wiederum selbst beliebig viele tiefere Schubfächer besitzen. Am Ende sammle ich dann nur noch die kompletten Bücherstapel der einzelnen Fächer in der richtigen Reihenfolge zusammen. Die Effektivität besteht darin, dass jeder Buchstabe jedes Wortes höchstens ein einziges Mal mit Asc(Mid(,,)) eingelesen werden muss. Wie geht das? Die Schubfächer sind bei mir lokale Arrays aus Listen, mit denen eine rekursive, also sich selbst aufrufende Funktion jongliert. Voila - das Ergebnis zufriedenstellend: 100.000 Wörter in weniger als einer Sekunde. BlitzMax: [AUSKLAPPEN] Const Wortanzahl% = 2000 |
||
![]() |
Ana |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ich hab mich (größtenteils) gegen die Tlist/Tmap entschieden, schien mir die eigentliche Aufgabe zu verfehlen, da ich dabei ja kaum sortieren müsste. Deshalb hab ich selbst einen Binärbaum, erstellt und ordne die Wörter entsprechend des Alphabets in ihm an. Danach wird er in der "inorder" - Reihenfolge traversiert und als Liste zurückgegeben.
BlitzMax: [AUSKLAPPEN] Rem Ana__COMMENT1__ |
||
Don't only practice your art,
but force your way into its secrets, for it and knowledge can raise human to divine |
![]() |
XeresModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Danke für eure Teilnahme und speziell an BlitzMoritz für den Essay artigen Beitrag!
Die Musterlösungen finden sich im Eingangspost. |
||
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group