¿Cómo ordenar la matriz de cadenas que contiene números negativos y positivos en c ++.?

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

stres una matriz de cadenas, con cada cadena en el formato de un entero, y debe realizar la clasificación en esta matriz a O(n log n)tiempo.

Las cadenas en strpueden representar enteros positivos y negativos. La longitud máxima de estas cadenas es de 1024 caracteres.

Sé que una solución de este problema es convertir las cadenas en números, luego compararlos aparte de esto; ¿Hay alguna otra solución a este problema?

Emp1
fuente
1024 caracteres, es decir, dígitos, necesitará enteros muy grandes para ...
Aconcagua
@RSahu mi error he editado la pregunta ahora
Emp1
@Aconcaguan sí, he usado la biblioteca de multiprecisión boost de cpp para eso
Emp1
Otra versión de la idea en las respuestas haciendo comparaciones basadas en cadenas: puede dividir la lista en partes negativas y no negativas, y luego usar dos funciones de comparación más simples para cada categoría para ordenar las partes.
aschepler

Respuestas:

13

Otra solución es implementar su propia función de comparación:

  • Verifique el primer carácter de ambas cadenas. Si uno comienza con un dígito y el otro comienza con un -, entonces la cadena que comienza con - es el número más pequeño.
  • Si ambas cadenas comienzan con un dígito, compare la longitud de las cadenas. La cadena más corta es el número más pequeño. Si ambas cadenas tienen la misma longitud, realice una comparación de cadena estándar.
  • Si ambas cadenas comienzan con -, entonces compare la longitud de las cadenas. La cadena más larga es el número más pequeño. Si ambas cadenas tienen la misma longitud, realice una comparación de cadena estándar, pero niegue el resultado.
usuario3386109
fuente
Pero debemos suponer que no hay ceros a la izquierda, estos deberían ser ignorados al considerar las longitudes de cadena. Los ceros negativos ( "-0"), si existen, se ordenarían frente a los normales, pero eso me parece bien ...
Aconcagua
3
Eso puede remediarse fácilmente. Use index from find_first_not_of("0")y páselos para compare()sobrecargar, que pide pos / len para ambos lados de la comparación.
Tanveer Badar
@Aconcagua Tienes razón en que no había considerado los ceros a la izquierda. Gracias a @ TanveerBadar por proporcionar la solución a eso. En cuanto a los ceros negativos, ordenarlos antes de los ceros positivos también me parece bien.
user3386109
12

Aquí hay un ejemplo mínimo y potencialmente insuficiente (no maneja ceros iniciales, espacios en blanco, etc.) que hace lo que desea.

Los comentarios explican lo que está haciendo. :)

#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
fuente
Ah, parece que la otra respuesta describe la misma lógica que he escrito en mi respuesta. Dejaré esto, aunque fueron los primeros. Usé código para expresar mi respuesta, él usó palabras. :)
druckermanly
La conversión explícita a bool no es necesaria si proporciona el tipo de retorno (final). Yo personalmente lo consideraría más legible. También podría usar en !=lugar de ^tener el mismo resultado para booleanos, pero el resultado ya es booleano, lo que hace que el reparto explícito quede obsoleto (y, además, los paréntesis ...).
Aconcagua
1
Maldición, me robaste mi (oportunidad de) respuesta: Mi demo en Coliru . ;-)
Scheff
Agradable @Aconcagua: estaba siendo flojo y escribía mis pensamientos en lugar de pensar en escribir código limpio. He adoptado sus sugerencias, ya que no cambia materialmente la respuesta.
druckermanly
Mientras que lambda puede estar bien, creo que la lambda es grande y que tiene sentido tener una función dedicada en su lugar ( less_as_number?).
Jarod42