Dies ist ein langer Text. Bitte bei mir tragen. Die Frage lautet: Gibt es einen funktionsfähigen Radix-Sortieralgorithmus an Ort und Stelle ?
Vorläufig
Ich habe eine große Anzahl kleiner Zeichenfolgen mit fester Länge , die nur die Buchstaben "A", "C", "G" und "T" (ja, Sie haben es erraten: DNA ) verwenden, die ich sortieren möchte.
Im Moment benutze ich std::sort
die verwendet Introsort in allen gängigen Implementierungen des STL . Das funktioniert ganz gut. Ich bin jedoch davon überzeugt, dass die Radix-Sortierung perfekt zu meinem Problem passt und in der Praxis viel besser funktionieren sollte .
Einzelheiten
Ich habe diese Annahme mit einer sehr naiven Implementierung getestet und für relativ kleine Eingaben (in der Größenordnung von 10.000) war dies wahr (zumindest mehr als doppelt so schnell). Die Laufzeit verschlechtert sich jedoch miserabel, wenn das Problem größer wird ( N > 5.000.000).
Der Grund liegt auf der Hand: Radix-Sortierung erfordert das Kopieren der gesamten Daten (tatsächlich mehr als einmal in meiner naiven Implementierung). Dies bedeutet, dass ich ~ 4 GiB in meinen Hauptspeicher gesteckt habe, was offensichtlich die Leistung beeinträchtigt. Selbst wenn dies nicht der Fall wäre, kann ich es mir nicht leisten, so viel Speicher zu verwenden, da die Problemgrößen sogar noch größer werden.
Anwendungsfälle
Idealerweise sollte dieser Algorithmus mit jeder Zeichenfolgenlänge zwischen 2 und 100 sowohl für DNA als auch für DNA5 (die ein zusätzliches Platzhalterzeichen „N“ zulässt) oder sogar für DNA mit IUPAC- Mehrdeutigkeitscodes (was zu 16 unterschiedlichen Werten führt) funktionieren . Mir ist jedoch klar, dass all diese Fälle nicht abgedeckt werden können, und ich bin mit jeder Geschwindigkeitsverbesserung zufrieden, die ich bekomme. Der Code kann dynamisch entscheiden, an welchen Algorithmus gesendet werden soll.
Forschung
Leider ist der Wikipedia-Artikel über Radix-Sortierung nutzlos. Der Abschnitt über eine In-Place-Variante ist völliger Müll. Der Abschnitt NIST-DADS zur Radix-Sortierung ist so gut wie nicht vorhanden. Es gibt ein vielversprechend klingendes Papier namens Efficient Adaptive In-Place Radix Sorting, das den Algorithmus „MSL“ beschreibt. Leider ist auch dieses Papier enttäuschend.
Insbesondere gibt es die folgenden Dinge.
Erstens enthält der Algorithmus mehrere Fehler und lässt vieles ungeklärt. Insbesondere wird der Rekursionsaufruf nicht detailliert beschrieben (ich gehe einfach davon aus, dass er einen Zeiger erhöht oder reduziert, um die aktuellen Verschiebungs- und Maskenwerte zu berechnen). Außerdem werden die Funktionen verwendet dest_group
und dest_address
keine Definitionen angegeben. Ich sehe nicht ein, wie ich diese effizient implementieren kann (dh in O (1); zumindest dest_address
nicht trivial).
Last but not least erreicht der Algorithmus die In-Place-Funktion, indem Array-Indizes mit Elementen innerhalb des Eingabearrays ausgetauscht werden. Dies funktioniert offensichtlich nur bei numerischen Arrays. Ich muss es für Saiten verwenden. Natürlich könnte ich einfach stark tippen und davon ausgehen, dass der Speicher es toleriert, einen Index dort zu speichern, wo er nicht hingehört. Dies funktioniert jedoch nur, solange ich meine Zeichenfolgen in 32 Bit Speicher komprimieren kann (unter der Annahme von 32-Bit-Ganzzahlen). Das sind nur 16 Zeichen (ignorieren wir für den Moment, dass 16> log (5.000.000)).
Ein anderes Papier eines der Autoren gibt überhaupt keine genaue Beschreibung, aber es gibt die Laufzeit von MSL als sublinear an, was absolut falsch ist.
Um es noch einmal zusammenzufassen : Gibt es Hoffnung, eine funktionierende Referenzimplementierung oder zumindest einen guten Pseudocode / eine gute Beschreibung einer funktionierenden Radix-Sorte zu finden, die an DNA-Strings funktioniert?