En programación competitiva, la eficiencia en la entrada de datos es crucial. Aquí exploramos varias técnicas:
cin
cin es la forma más sencilla de leer datos en C++. Sin embargo, es notablemente más lenta que scanf, aunque esta diferencia se reduce significativamente si se desactiva la sincronización con la E/S estándar de C. Una ventaja de cin es su capacidad para leer diversos tipos de datos sin necesidad de epsecificar un formato explícito para cada uno, a diferencia de scanf. No obstante, puede ser menos flexible para leer formatos de entrada complejos o específicos.
cin devuelve un estado que indica el fin del archivo (EOF) cuando se encuentra.
scanf
scanf, originario de C, ofrece una velocidad de lectura considerablemente mayor que cin. Al utilizar scanf, es fundamental seleccionar el especificador de formato correcto dentro de las comillas y asegurarse de pasar las variables por referencia (usando el operador &). Una limitación importante es que scanf no puede leer directamente variables de tipo std::string.
Especificadores de Formato Comunes
%d: Para leer un entero de tipoint.%lld: Para leer un entero de tipolong long.%f: Para leer un número de punto flotante de tipofloat.%lf: Para leer un número de punto flotanet de tipodouble.%Lf: Para leer un número de punto flotante de tipolong double.%c: Para leer un único carácter.%s: Para leer una cadena de caracteres (a un array dechar).
El uso de un especificador incorrecto puede provocar errores de ejecución.
Valor de Retorno y Entrada de Longitud Indeterminada
Al igual que cin, scanf devuelve el número de elementos leídos con éxito. Si se alcanza el fin del archivo, devuelve EOF (-1). Esta característica es útil para manejar entradas donde el número de datos no se conoce de antemano:
int count = 0;
int data[2005];
while (scanf("%d", &data[++count]) != EOF);
count--; // Ajustar el contador porque se incrementó una vez más al leer EOF
Lectura de Datos con Formato Fijo
Cuando los datos de entrada siguen un patrón específico, como una fecha con formato "hh:mm", se pueden incluir caracteres literales (como el dos puntos ':') entre los especificadores de formato en scanf. Por ejemplo, scanf("%d:%d", &hours, &minutes). Esto requiere que la entrada coincida exactamente con el formato especificado.
Ejemplo: Leer datos con formato "[ID]año/mes/día - hora:minuto:segundo":
int id, year, month, day, hour, minute, second;
scanf("[%d]%d/%d/%d - %d:%d:%d", &id, &year, &month, &day, &hour, &minute, &second);
getchar
getchar lee un solo carácter y puede ser la base para implementar rutinas de lectura rápida (fast I/O) que superan en velocidad a cin y scanf, además de ser más flexibles. Al igual que las otras funciones, devuelve EOF al final del archivo.
getchar devuelve el valor ASCII del carácter leído. Para convertir un dígito ASCII a su valor numérico, se le resta el valor ASCII de '0' (que es 48).
Implementación de Lectura Rápida
Una rutina básica de lectura rápida lee caracteres hasta encontrar un dígito, luego lee los dígitos hasta que termina el número, y finalmente convierte la secuencia de dígitos leída en un valor entero:
int fast_read() {
int value = 0;
int sign = 1; // 1 para positivo, -1 para negativo
char character;
// Ignorar caracteres no numéricos al inicio
character = getchar();
while (character < '0' || character > '9') {
if (character == '-') {
sign = -1;
}
character = getchar();
}
// Leer los dígitos del número
while (character >= '0' && character <= '9') {
value = value * 10 + (character - '0'); // Convertir ASCII a número
character = getchar();
}
return value * sign;
}
Lectura de Caracteres Específicos
Se pueden adaptar métodos similares para leer secuencias específicas de caracteres, ignorando los demás.
Ejemplo 1: Leer una cadena binaria hasta encontrar un carácter no binario:
int n = 0;
bool binary_digits[105];
char current_char = getchar();
// Avanzar hasta el primer carácter '0' o '1'
while(current_char != '0' && current_char != '1') {
current_char = getchar();
}
// Leer la secuencia binaria
while(current_char == '0' || current_char == '1') {
binary_digits[++n] = (current_char == '1'); // Almacenar como booleano
current_char = getchar();
}
Ejemplo 2: Contar espacios en un texto hasta el fin del archivo:
int space_count = 0;
char ch = getchar();
while (ch != EOF) {
if (ch == ' ') {
space_count++;
}
ch = getchar();
}
Nota sobre la entrada rápida: Si bien getchar puede ser muy rápido, métodos basados en fread suelen ser aún más eficientes para la lectura masiva de datos. Al leer desde la consola, se necesita presionar Ctrl+Z (en Windows) o Ctrl+D (en Linux/macOS) para simular el fin del archivo (EOF).