Wie sortiere ich ein Array von Strings, die sowohl negative als auch positive Zahlen in c ++ enthalten?

8
String str[]={"-123","89","-10","456"};

strist ein Array von Zeichenfolgen, wobei jede Zeichenfolge das Format einer Ganzzahl hat, und Sie müssen dieses Array O(n log n)rechtzeitig sortieren .

Die Zeichenfolgen in strkönnen sowohl positive als auch negative Ganzzahlen darstellen. Die maximale Länge dieser Zeichenfolgen beträgt 1024 Zeichen.

Ich weiß, dass eine Lösung dieses Problems darin besteht, die Zeichenfolgen in Zahlen umzuwandeln und sie dann zu vergleichen. Gibt es eine andere Lösung für dieses Problem?

Emp1
quelle
1024 Zeichen - dh Ziffern - Sie benötigen sehr große Ganzzahlen für ...
Aconcagua
@ RSahu mein Fehler Ich habe die Frage jetzt bearbeitet
Emp1
@Aconcaguan ja, ich habe Boost Multiprecision Bibliothek von CPP dafür verwendet
Emp1
Eine andere Version der Idee in den Antworten, die auf Zeichenfolgen basierende Vergleiche durchführen: Sie können die Liste in negative und nicht negative Teile unterteilen und dann zwei einfachere Vergleichsfunktionen für jede Kategorie verwenden, um die Teile zu sortieren.
Aschepler

Antworten:

13

Eine andere Lösung besteht darin, eine eigene Vergleichsfunktion zu implementieren:

  • Überprüfen Sie das erste Zeichen beider Zeichenfolgen. Wenn eine mit einer Ziffer beginnt und die andere mit einer -, ist die Zeichenfolge, die mit beginnt, - die kleinere Zahl.
  • Wenn beide Zeichenfolgen mit einer Ziffer beginnen, vergleichen Sie die Länge der Zeichenfolgen. Die kürzere Zeichenfolge ist die kleinere Zahl. Wenn beide Zeichenfolgen dieselbe Länge haben, führen Sie einen Standard-Zeichenfolgenvergleich durch.
  • Wenn beide Zeichenfolgen mit beginnen -, vergleichen Sie die Länge der Zeichenfolgen. Die längere Zeichenfolge ist die kleinere Zahl. Wenn beide Zeichenfolgen dieselbe Länge haben, führen Sie einen Standard-Zeichenfolgenvergleich durch, negieren Sie jedoch das Ergebnis.
user3386109
quelle
Wir müssen jedoch davon ausgehen, dass es keine führenden Nullen gibt. Diese müssten ignoriert werden, wenn Zeichenfolgenlängen berücksichtigt werden. Negative Nullen ( "-0"), falls vorhanden, würden vor den normalen sortiert, aber das scheint mir in Ordnung zu sein ...
Aconcagua
3
Das kann leicht behoben werden. Verwenden Sie den Index von find_first_not_of("0")und übergeben Sie diese an die compare()Überladung, die für beide Vergleichsseiten nach pos / len fragt.
Tanveer Badar
@Aconcagua Sie haben Recht, dass ich nicht an führende Nullen gedacht hatte. Vielen Dank an @ TanveerBadar für die Bereitstellung der Lösung dafür. Was negative Nullen betrifft, scheint es mir auch in Ordnung zu sein, sie vor positiven Nullen zu sortieren.
user3386109
12

Hier ist ein minimales und möglicherweise unzureichendes Beispiel (behandelt keine führenden Nullen, Leerzeichen usw.), das das tut, was Sie möchten.

Die Kommentare erklären, was es tut. :) :)

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int main() {
  std::vector<std::string> strings = {
      "-1", "-1", "-20", "-4", "3", "0", "-0", "1", "20", "20", "44020",
  };

  // Assumes everything in "strings" has no whitespace in it.
  // Assumes everything in "strings" does not have leading zeroes.
  // Assumes everything in "strings" is an ascii representaion of an integer.
  // Assumes everything in "strings" is nonempty.
  std::sort(strings.begin(), strings.end(),
            [](const std::string &a, const std::string &b) {
              const bool a_is_negative = a[0] == '-';
              const bool b_is_negative = b[0] == '-';
              if (a_is_negative != b_is_negative) {
                // If they have different signs, then whichever is negative is
                // smaller.
                return a_is_negative;
              } else if (a.length() != b.length()) {
                // If they have the same sign, then whichever has more
                // characters is larger in magnitude. When the sign is negative,
                // the longer (more digits) number is "more negative". When
                // positive, the longer (more digits) number is "more positive".
                return (a.length() < b.length()) != a_is_negative;
              } else {
                // Otherwise a lexicographic comparison of "a" and "b" will
                // determine which string is larger in magnitude. Using the same
                // logic above, we account for the "negative vs. positive"
                // comparison.
                return (a < b) != a_is_negative;
              }
            });

  for (const auto &str : strings) {
    std::cout << str << " ";
  }
  std::cout << std::endl;
}
druckermanly
quelle
Ah, die andere Antwort beschreibt die gleiche Logik, die ich in meiner Antwort geschrieben habe. Ich werde das aufgeben, obwohl sie die ersten waren. Ich habe Code verwendet, um meine Antwort auszudrücken, er hat Wörter verwendet. :)
druckermanly
Eine explizite Konvertierung in bool ist nicht erforderlich, wenn Sie einen (nachfolgenden) Rückgabetyp angeben. Ich persönlich würde das für lesbarer halten. Sie können auch verwenden, !=anstatt ^dasselbe Ergebnis für Boolesche Werte zu haben, aber das Ergebnis ist bereits boolesch, wodurch die explizite Umwandlung (und zusätzlich die Klammern ...) veraltet sind.
Aconcagua
1
Verdammt, du hast meine (Gelegenheit) Antwort gestohlen: Meine Demo auf Coliru . ;-)
Scheff
Nice @Aconcagua - Ich war faul und schrieb meine Gedanken, anstatt darüber nachzudenken, sauberen Code zu schreiben. Ich habe Ihre Vorschläge übernommen, da dies die Antwort nicht wesentlich ändert.
Druckermanly
Während Lambda in Ordnung sein kann, denke ich, dass das Lambda groß ist und dass es sinnvoll ist, stattdessen eine dedizierte Funktion zu haben ( less_as_number?).
Jarod42