Ciclo While
Aprende a usar while y do-while para repetir cuando no sabes cuántas veces
¿Cuándo usar while?
El ciclo for es perfecto cuando sabes cuántas veces repetir. Pero, ¿qué pasa cuando no lo sabes? Por ejemplo:
- "Sigue pidiendo una contraseña mientras sea incorrecta."
- "Divide el número entre 2 mientras sea par."
- "Lee datos mientras haya datos disponibles."
Para estas situaciones usamos el ciclo while.
Analogía: Imagina que estás llenando un vaso con agua. No sabes cuántos segundos tardará, pero sigues mientras el vaso no esté lleno.
El ciclo while
while (condición) {
// Este código se repite MIENTRAS la condición sea verdadera
}
Flujo:
- Evalúa la condición.
- Si es
true, ejecuta el bloque. - Vuelve al paso 1.
- Si es
false, el ciclo termina.
int i = 1;
while (i <= 5) {
cout << i << " ";
i++; // ¡No olvides actualizar la variable!
}
// Salida: 1 2 3 4 5
Paso a paso:
| Iteración | i | ¿i <= 5? | Acción |
|---|---|---|---|
| 1 | 1 | Sí | Imprime 1, i → 2 |
| 2 | 2 | Sí | Imprime 2, i → 3 |
| 3 | 3 | Sí | Imprime 3, i → 4 |
| 4 | 4 | Sí | Imprime 4, i → 5 |
| 5 | 5 | Sí | Imprime 5, i → 6 |
| 6 | 6 | No | FIN |
¡Cuidado con los ciclos infinitos! Si la condición nunca se vuelve falsa, el programa se ejecuta para siempre. Siempre asegúrate de que algo dentro del ciclo eventualmente haga la condición falsa.
// ❌ CICLO INFINITO - la condición nunca cambia
int x = 1;
while (x > 0) {
cout << x << endl;
// Olvidamos cambiar x
}
while vs for
Cualquier for se puede reescribir como while y viceversa:
// Con for
for (int i = 0; i < n; i++) {
cout << i << endl;
}
// Equivalente con while
int i = 0;
while (i < n) {
cout << i << endl;
i++;
}
¿Cuándo usar cuál?
for: Cuando sabes cuántas veces repetir (o tienes un rango claro).while: Cuando la repetición depende de una condición que puede cambiar de formas más complejas.
El ciclo do-while
La diferencia con while es que do-while siempre ejecuta el bloque al menos una vez, porque la condición se evalúa después:
do {
// Se ejecuta al menos una vez
} while (condición); // Nota el punto y coma al final
Analogía: "Prueba el platillo, y si no te gusta, prueba otro." (Primero pruebas, luego decides.)
int opcion;
do {
cout << "1. Jugar" << endl;
cout << "2. Opciones" << endl;
cout << "3. Salir" << endl;
cout << "Elige: ";
cin >> opcion;
if (opcion < 1 || opcion > 3) {
cout << "Opción no válida, intenta de nuevo." << endl;
}
} while (opcion != 3);
cout << "¡Hasta luego!" << endl;
Este menú se muestra al menos una vez, y se repite hasta que el usuario elija 3.
Usos comunes del while
1. Extraer dígitos de un número
int n = 12345;
while (n > 0) {
int digito = n % 10; // Último dígito
cout << digito << " ";
n /= 10; // Quitar el último dígito
}
// Salida: 5 4 3 2 1 (los dígitos en orden inverso)
Paso a paso:
n | n % 10 (dígito) | n / 10 (nuevo n) |
|---|---|---|
| 12345 | 5 | 1234 |
| 1234 | 4 | 123 |
| 123 | 3 | 12 |
| 12 | 2 | 1 |
| 1 | 1 | 0 |
| 0 | FIN |
2. Suma de dígitos
int n;
cin >> n;
int suma = 0;
while (n > 0) {
suma += n % 10;
n /= 10;
}
cout << "Suma de dígitos: " << suma << endl;
Entrada: 1234
Salida: Suma de dígitos: 10 (porque 1+2+3+4 = 10)
3. Contar dígitos
int n;
cin >> n;
int digitos = 0;
int temp = n;
if (temp == 0) digitos = 1; // Caso especial: el 0 tiene 1 dígito
while (temp > 0) {
digitos++;
temp /= 10;
}
cout << n << " tiene " << digitos << " dígitos" << endl;
4. Convertir decimal a binario
int n;
cin >> n;
string binario = "";
while (n > 0) {
binario = (char)('0' + n % 2) + binario; // Agregar al inicio
n /= 2;
}
if (binario.empty()) binario = "0";
cout << binario << endl;
Entrada: 13
Salida: 1101 (porque 13 = 8+4+1 = )
5. Algoritmo de Euclides (GCD)
El máximo común divisor usando el algoritmo de Euclides:
int a, b;
cin >> a >> b;
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
cout << "GCD: " << a << endl;
Paso a paso con a=12, b=8:
a | b | a % b |
|---|---|---|
| 12 | 8 | 4 |
| 8 | 4 | 0 |
| 4 | 0 | FIN |
GCD(12, 8) = 4. ✓
6. Leer hasta EOF (fin de archivo)
int x;
while (cin >> x) {
cout << x * 2 << '\n';
}
El ciclo continúa mientras haya datos para leer. Cuando el juez ya no envía más datos, cin >> x devuelve false y el ciclo termina.
7. Buscar algo específico
int n;
cin >> n;
// Encontrar la primera potencia de 2 mayor o igual a n
int potencia = 1;
while (potencia < n) {
potencia *= 2;
}
cout << potencia << endl;
Entrada: 10
Salida: 16 (porque 1, 2, 4, 8, 16 ≥ 10)
Patrones avanzados
Simulación paso a paso
Muchos problemas de competencia te piden simular un proceso:
// Problema: Una bacteria se duplica cada hora.
// ¿Cuántas horas hasta que haya más de 1000 bacterias?
int bacterias = 1;
int horas = 0;
while (bacterias <= 1000) {
bacterias *= 2;
horas++;
}
cout << horas << " horas" << endl;
// Salida: 10 horas (2^10 = 1024 > 1000)
Secuencia de Collatz
Una secuencia famosa: empezando de cualquier número, si es par divídelo entre 2, si es impar multiplícalo por 3 y suma 1. Eventualmente llegas a 1.
int n;
cin >> n;
int pasos = 0;
while (n != 1) {
cout << n << " -> ";
if (n % 2 == 0) {
n /= 2;
} else {
n = 3 * n + 1;
}
pasos++;
}
cout << 1 << endl;
cout << "Pasos: " << pasos << endl;
Entrada: 6
Salida: 6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 (8 pasos)
while(t--): el patrón de múltiples casos
Muchos problemas en competencias tienen múltiples casos de prueba:
int t;
cin >> t;
while (t--) {
// Resolver un caso
int a, b;
cin >> a >> b;
cout << a + b << '\n';
}
¿Cómo funciona while(t--)?
- Evalúa
t(si no es 0, es verdadero). - Decrementa
t. - Si era verdadero, ejecuta el cuerpo.
Si t = 3, ejecuta el cuerpo 3 veces (con t tomando valores 2, 1, 0 internamente).
Ejercicio de práctica
Lee un número positivo y determina si es una potencia de 2. Un número es potencia de 2 si se puede obtener dividiendo repetidamente entre 2 hasta llegar a 1.
Entrada: 16 → Salida: Si (porque 16 → 8 → 4 → 2 → 1)
Entrada: 12 → Salida: No (porque 12 → 6 → 3, y 3 no es divisible entre 2)
Ver solución
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n <= 0) {
cout << "No" << endl;
return 0;
}
while (n > 1) {
if (n % 2 != 0) {
cout << "No" << endl;
return 0;
}
n /= 2;
}
cout << "Si" << endl;
return 0;
}
Alternativa elegante usando la propiedad de bits: una potencia de 2 en binario tiene exactamente un 1 (100...0). Entonces n & (n-1) es 0:
if (n > 0 && (n & (n - 1)) == 0) {
cout << "Si" << endl;
} else {
cout << "No" << endl;
}
Siguiente paso
Aprende sobre Funciones para organizar tu código en bloques reutilizables.
