Sortieren array von ganzen zahlen lexikographisch C++
Ich möchte sozusagen ein großes Integer-array (sagen wir 1 Mio Elemente) lexikographisch.
Beispiel:
input [] = { 100, 21 , 22 , 99 , 1 , 927 }
sorted[] = { 1 , 100, 21 , 22 , 927, 99 }
Ich habe es mit der einfachsten Methode:
- wandeln Sie alle zahlen in strings (sehr teuer, weil es dauern wird, riesige Speicher)
- verwenden
std:sort
mitstrcmp
als Vergleich-Funktion - zurück konvertieren der strings in Ganzzahlen
Gibt es eine bessere Methode als das?
- Wie machst du deine Umbauten?
- Wie groß können die zahlen sein?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verwenden
std::sort()
mit einem passenden Vergleich-Funktion. Dies reduziert die Anforderungen an den Arbeitsspeicher.Die Vergleich-Funktion verwenden können
n % 10
,n /10 % 10
,n /100 % 10
etc. um auf die einzelnen Ziffern (für positive zahlen; negative Ganzzahlen arbeiten ein bisschen anders).Zu leisten, die benutzerdefinierte Sortierreihenfolge, die Sie bieten kann, einen Komparator zu
std::sort
. In diesem Fall, es wird etwas komplexer, mit Logarithmen zu inspizieren einzelnen Ziffern der Zahl in der Basis 10.Hier ist ein Beispiel — Kommentare inline beschreiben, was Los ist.
Demo
Es gibt schnellere Wege, um berechnen Sie die Anzahl der Ziffern in einer Zahl, aber der oben wird Ihnen den Einstieg.
DIV
,POW
undMOD
über die Einführung von floating-point-nastinesses.std::ceil(std::log(lhs+1)/std::log(BASE))
können aus der durch eine.Hier ist ein weiterer Algorithmus, der einige der Berechnung vor der Sortierung. Es scheint zu sein, ziemlich schnell, trotz der zusätzlichen kopieren (siehe Vergleiche).
Hinweis:
std::numeric_limits<int>::max()/10
N. B. optimieren Sie
count_digits
undmy_pow10
; für Beispiel, siehe Drei Tipps zur Optimierung für C++ von Andrei Alexandrescu und Irgendeiner Weise schneller ist als pow() zur Berechnung einer ganzzahligen Potenz von 10 in C++?Helfer:
Algorithmus (Hinweis - nicht in-place):
Beispiel:
#ifdef LIGHTNESS
😀 ich mag Ihr Ansatz, caching, solange Sie sind sich bewusst, Ihre storage-Anforderungen. OP sagte, gab es reichlich input. Warum vermeiden Sieconst
imlexicographic_pair_helper
?-O2
, aber in meiner VM.. besser es selbst zu versuchen. (Ehrlich gesagt, ich bin mir auch nicht sicher, ob ich Das Richtige mit meinem einfachen Vergleich.)int
, 3 multipliziert werden durch 1.000.000.000, und dass überläufe. Auch sollte berücksichtigt werden, dass einlog10
zurückkehren könnte eine etwas ungenaue Ergebnis.log10
undpow
mittlerweile.log10
undpow
wie ich sagte und fest ein copy-und-paste-Fehler (die Anpassung der Verteilung fehlte im Vergleich Beispiel). Nun bekomme ich genaue übereinstimmungen zwischen Leichtigkeit' version und mir.Ich glaube, die folgenden Werke als eine Art Vergleich-Funktion für positive ganze zahlen sind, sofern der integer-Typ verwendet wird, ist wesentlich schmaler als die
double
Typ (z.B. 32-bit -int
- und 64-bit -double
) und dielog10
routine verwendet, gibt genau die richtigen Ergebnisse für die genauen Potenzen von 10 (was eine gute Implementierung hat):Es funktioniert durch den Vergleich der mantissas der Logarithmen. Die mantissas die Nachkommastellen des Logarithmus, und Sie zeigen den Wert der signifikanten stellen einer Zahl ohne den Umfang (z.B. die Logarithmen von 31, 3.1 und 310 haben genau die gleiche Mantisse).
Zweck der
fabs(fx - fy) < limit
ist es, für Fehler bei der Einnahme der Logarithmus, die auftreten, weil beide Implementierungenlog10
sind unvollkommen, und da die floating-point-format Kräfte einige Fehler. (Der integer-Teile von den Logarithmen von 31 und 310 verwenden eine unterschiedliche Anzahl von bits, so gibt es eine unterschiedliche Anzahl von bits für die Mantisse, so dass Sie am Ende abgerundet, um leicht unterschiedliche Werte.) Solange der integer-Typ ist wesentlich schmaler als diedouble
Typ, der berechnetlimit
wird viel größer sein, als die Fehler inlog10
. So, der testfabs(fx - fy) < limit
im wesentlichen sagt uns, ob zwei berechnete mantissas wäre gleich, wenn exakt berechnet.Wenn die mantissas unterscheiden, zeigen Sie die lexikographische Ordnung, also kehren wir
fx < fy
. Wenn Sie gleich sind, dann der ganzzahlige Anteil des Logarithmus sagt uns das Bestellformular ein, damit wir zurücklx < ly
.Es ist einfach um zu testen, ob
log10
korrekte Ergebnisse zurückgegeben, für jede Leistung von zehn, da es so wenige von Ihnen gibt. Wenn nicht, Anpassungen können leicht vorgenommen werden: Einfügenif (1-fx < limit) fx = 0; if (1-fu < limit) fy = 0;
. Dies ermöglicht, wennlog10
gibt so etwas wie 4.99999... wenn es sollte zurückgegeben haben, 5.Diese Methode hat den Vorteil, nicht mit Schleifen oder division (die ist zeitaufwendig, die auf vielen Prozessoren).
Die Aufgabe klingt wie eine Natürliche Passform für ein MSD-Variante von Radix-Sort mit Polsterung ( http://en.wikipedia.org/wiki/Radix_sort ).
Hängt davon ab, wie viel code, den Sie wollen, um sich werfen. Die einfachen Codes wie die anderen zu zeigen ist O(log n) Komplexität, während eine vollständig optimierte radix-sort wäre O(kn).
Eine kompakte Lösung, wenn alle Ihre zahlen sind von nicht negativer und Sie sind klein genug, so dass die Multiplikation um 10 nicht zu einem überlauf führen:
Führen Sie es wie folgt:
Könnten Sie versuchen, mit dem % - operator, um Ihnen den Zugang zu jeder einzelnen Ziffer eg 121 % 100 geben Sie die erste Ziffer und überprüfen Sie, dass Weg, aber du musst einen Weg finden, wie etwa die Tatsache, dass Sie verschiedene Größen haben.
So finden Sie den maximalen Wert in der Reihe. Ich weiß nicht, ob es eine Funktion dafür eingebaut, die Sie könnten versuchen.
Diese Funktion gibt die Anzahl der Ziffern in der Zahl
Lassen Sie Anzahl der Ziffern im max gleich n ist.
Sobald Sie diese öffnen einer for-Schleife im format
for (int i = 1; i < n ; i++)
dann können Sie gehen Sie durch Ihre und mit "data[i] % (10^(n-i))", um Zugang zu der ersten Ziffer, dann
Sortieren, und dann auf die nächste iteration erhalten Sie Zugriff auf die zweite Stelle. Ich weiß nicht, wie Sie Sie zu Sortieren, obwohl.
Es wird nicht funktionieren, für negative zahlen, und Sie haben zu umgehen, Daten[i] % (10^(n-i)) und kehrt sich für zahlen mit weniger stellen als max
121 / 100
und121 - 121 % 100
wird den Zugang zu der ersten Ziffer.Überlastung der < operator zum vergleichen von zwei ganzen zahlen lexikographisch. Für jede ganze Zahl, finden die kleinste 10^k, die nicht weniger als die angegebene Ganzzahl. Vergleichen Sie die Ziffern nacheinander.
bool(int, int)
Durchführung lexikographischen Vergleich in global-oder Datei-Bereich, würde ich vorschlagen, eine genauere Angabe alsless
. 😛const
; nicht zu erwähnen, einige bessere Variablennamen.Während einige andere Antworten hier (Leichtigkeit ist, notbad s) zeigen sich schon Recht guten code, ich glaube, ich kann hinzufügen, eine Lösung, die möglicherweise noch performant (da es erfordert weder die division noch die macht in jeder Schleife; Sie erfordert aber die floating-point-Arithmetik, die wiederum vielleicht machen Sie es langsam, und möglicherweise ungenau für große zahlen):
Obwohl ich muss zugeben, dass ich noch nicht getestet, die Leistung noch nicht.
Ist hier der dumme Lösung, die keine floating-point-tricks. Es ist so ziemlich das gleiche wie der string-Vergleich, aber nicht ein string pro sagen, nicht auch mit negativen zahlen, das zu tun, fügen Sie eine Sektion an der Spitze...
Es ist schnell, und ich bin sicher, es ist möglich es schneller zu machen, immer noch, aber es funktioniert und es ist dumm genug, um zu verstehen...
EDIT: ich aß dump viel code, aber hier ist ein Vergleich aller Lösungen so weit..
std::numeric_limits<int>::digits10
😉Basierend auf @Oswald ' s Antwort, unten ist etwas code, der das gleiche tut.
Eingang: 1 2 3 4 5 6 7 8 9 10 11 12
Ausgabe: 1 10 11 12 2 3 4 5 6 7 8 9