Estructuras de Controlc++forciclosloopsiteración

Ciclo For

Domina el ciclo for para repetir instrucciones de forma controlada

OOI Oaxaca9 de febrero de 20268 min read

¿Por qué necesitamos ciclos?

Imagina que quieres imprimir los números del 1 al 100. Sin ciclos, tendrías que escribir 100 líneas de cout. ¿Y si fueran un millón? Imposible.

Los ciclos (o loops) permiten que tu programa repita un bloque de código muchas veces sin tener que escribirlo múltiples veces. Es como decirle a alguien: "Repite esto 100 veces" en lugar de darle la misma instrucción 100 veces.

El ciclo for

El for es el ciclo más usado en programación competitiva. Es perfecto cuando sabes cuántas veces quieres repetir algo.

for (inicialización; condición; actualización) {
    // Código que se repite
}

Ejemplo básico:

for (int i = 1; i <= 5; i++) {
    cout << i << endl;
}

Salida:

1
2
3
4
5

Las tres partes del for

Desglosemos for (int i = 1; i <= 5; i++):

  1. Inicialización (int i = 1): Se ejecuta una sola vez al inicio. Aquí creamos nuestra variable contadora i y le damos su valor inicial.

  2. Condición (i <= 5): Se verifica antes de cada repetición. Si es verdadera, se ejecuta el cuerpo. Si es falsa, el ciclo termina.

  3. Actualización (i++): Se ejecuta después de cada repetición. Normalmente incrementa o decrementa el contador.

Flujo paso a paso:

1. i = 1         (inicialización)
2. ¿i <= 5? Sí   (condición) → ejecuta el cuerpo → imprime 1
3. i++ → i = 2   (actualización)
4. ¿i <= 5? Sí   → ejecuta el cuerpo → imprime 2
5. i++ → i = 3
6. ¿i <= 5? Sí   → ejecuta el cuerpo → imprime 3
7. i++ → i = 4
8. ¿i <= 5? Sí   → ejecuta el cuerpo → imprime 4
9. i++ → i = 5
10. ¿i <= 5? Sí  → ejecuta el cuerpo → imprime 5
11. i++ → i = 6
12. ¿i <= 5? No  → FIN del ciclo

Analogía: Piensa en dar vueltas a una pista de atletismo. La inicialización es ponerte en la línea de salida. La condición es "¿ya di las vueltas necesarias?". La actualización es contar una vuelta más.

Variaciones del for

Contar hacia atrás

for (int i = 10; i >= 1; i--) {
    cout << i << " ";
}
// Salida: 10 9 8 7 6 5 4 3 2 1

Avanzar de 2 en 2

for (int i = 0; i <= 10; i += 2) {
    cout << i << " ";
}
// Salida: 0 2 4 6 8 10

Empezar desde 0 (lo más común en programación)

En programación, es convención empezar a contar desde 0:

for (int i = 0; i < 5; i++) {
    cout << i << " ";
}
// Salida: 0 1 2 3 4  (5 números: del 0 al 4)
💡

La forma más estándar de repetir algo N veces es: for (int i = 0; i < n; i++). Esto da exactamente n iteraciones con i tomando valores de 0 a n-1. Te acostumbrarás rápidamente a esta notación.

Recorrer un arreglo

int arr[] = {10, 20, 30, 40, 50};
int n = 5;

for (int i = 0; i < n; i++) {
    cout << "arr[" << i << "] = " << arr[i] << endl;
}
// arr[0] = 10
// arr[1] = 20
// arr[2] = 30
// arr[3] = 40
// arr[4] = 50

For-each (basado en rango)

C++ moderno tiene una forma más elegante de recorrer colecciones:

vector<int> v = {10, 20, 30, 40, 50};

for (int x : v) {
    cout << x << " ";
}
// Salida: 10 20 30 40 50

Se lee como "para cada x en v". Es más limpio cuando no necesitas el índice.

Ciclos anidados

Puedes poner un ciclo dentro de otro:

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        cout << "(" << i << "," << j << ") ";
    }
    cout << endl;
}

Salida:

(1,1) (1,2) (1,3)
(2,1) (2,2) (2,3)
(3,1) (3,2) (3,3)

Analogía: Piensa en un reloj. La manecilla de los minutos (ciclo interno j) da una vuelta completa por cada movimiento de la manecilla de las horas (ciclo externo i).

Tabla de multiplicar

int n;
cin >> n;

for (int i = 1; i <= 10; i++) {
    cout << n << " x " << i << " = " << n * i << endl;
}

Entrada: 7 Salida:

7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
...
7 x 10 = 70

Patrón de triángulo

int n = 5;
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= i; j++) {
        cout << "* ";
    }
    cout << endl;
}

Salida:

*
* *
* * *
* * * *
* * * * *

break y continue

break: salir del ciclo inmediatamente

for (int i = 1; i <= 100; i++) {
    if (i == 5) {
        break;  // Sale del ciclo cuando i llega a 5
    }
    cout << i << " ";
}
// Salida: 1 2 3 4

Analogía: Estás buscando tu libro en una estantería. Revisas libro por libro, y cuando lo encuentras, paras de buscar.

continue: saltar a la siguiente iteración

for (int i = 1; i <= 10; i++) {
    if (i % 3 == 0) {
        continue;  // Salta los múltiplos de 3
    }
    cout << i << " ";
}
// Salida: 1 2 4 5 7 8 10

Analogía: Estás sirviendo comida a una fila de personas. Si alguien ya comió, lo saltas y sigues con el siguiente.

Patrones comunes en competencias

Leer N números y sumarlos

int n;
cin >> n;

int suma = 0;
for (int i = 0; i < n; i++) {
    int x;
    cin >> x;
    suma += x;
}
cout << suma << endl;

Encontrar el máximo y mínimo

int n;
cin >> n;

int maximo = -1e9;  // Un valor muy pequeño
int minimo = 1e9;    // Un valor muy grande

for (int i = 0; i < n; i++) {
    int x;
    cin >> x;
    maximo = max(maximo, x);
    minimo = min(minimo, x);
}

cout << "Max: " << maximo << ", Min: " << minimo << endl;

Contar elementos que cumplen una condición

int n;
cin >> n;

int pares = 0;
for (int i = 0; i < n; i++) {
    int x;
    cin >> x;
    if (x % 2 == 0) {
        pares++;
    }
}
cout << "Hay " << pares << " números pares" << endl;

Generar todos los pares

int n;
cin >> n;

for (int i = 0; i < n; i++) {
    for (int j = i + 1; j < n; j++) {
        cout << "Par: (" << i << ", " << j << ")" << endl;
    }
}

Nota que j empieza en i + 1 para evitar pares repetidos.

Complejidad de los ciclos

  • Un ciclo simple (for i = 0..n): O(n)O(n) operaciones.
  • Dos ciclos anidados (for i..n, for j..n): O(n2)O(n^2) operaciones.
  • Tres ciclos anidados: O(n3)O(n^3) operaciones.
// O(n) - funciona para n hasta ~10^8
for (int i = 0; i < n; i++) { ... }

// O(n²) - funciona para n hasta ~10^4
for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++) { ... }

// O(n³) - funciona para n hasta ~500
for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
        for (int k = 0; k < n; k++) { ... }
⚠️

En competencias, una regla general es que una computadora puede hacer aproximadamente 10810^8 operaciones por segundo. Si tu solución tiene O(n2)O(n^2) y n=105n = 10^5, eso son 101010^{10} operaciones... ¡demasiadas! Necesitarás un algoritmo más eficiente.

Ejercicio de práctica

Imprime todos los números primos del 2 al N. Un número primo es aquel que solo es divisible entre 1 y sí mismo.

Entrada: 20 Salida: 2 3 5 7 11 13 17 19

Ver solución
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    for (int i = 2; i <= n; i++) {
        bool esPrimo = true;

        for (int j = 2; j * j <= i; j++) {
            if (i % j == 0) {
                esPrimo = false;
                break;
            }
        }

        if (esPrimo) {
            cout << i << " ";
        }
    }
    cout << endl;

    return 0;
}

¿Por qué j * j <= i en lugar de j <= i? Porque si i tiene un divisor mayor que i\sqrt{i}, necesariamente tiene otro menor que i\sqrt{i}. Así revisamos muchos menos números. Por ejemplo, para verificar si 36 es primo, solo necesitamos revisar hasta 6 (porque 62=366^2 = 36).

Siguiente paso

Aprende el Ciclo While para repetir cuando no sabes de antemano cuántas veces necesitas.