Estructuras de Control y Modularidad

2.07 · Patrones: Contadores, Acumuladores y Centinelas

PF-207 ⏱ 90 min ⭐ 120 XP intermedio

🎯 Objetivo de aprendizaje

Al terminar este tema vas a poder:

  1. Reconocer los 5 patrones algorítmicos más usados en bucles: suma, promedio, mayor/menor, búsqueda, conteo por condición.
  2. Aplicar cada patrón con while, do-while y for según el contexto.
  3. Combinar patrones para resolver problemas más complejos (ej: "suma de los pares" = filtro + acumulador).
  4. Usar el patrón "mayor/menor" con el "algoritmo del centinela" para encontrar extremos en secuencias.
  5. Resolver problemas de entrevistas junior usando estos patrones (los 5 más comunes).
  6. Trazar manualmente cualquier combinación de patrones con datos de prueba.

Los patrones son el 80% de los problemas algorítmicos que vas a enfrentar en tu carrera: exámenes, entrevistas, trabajo real. Si dominas estos 5 patrones, puedes resolver el 80% de los problemas típicos de un junior.

🧠 Teoría y conceptos — 2.7.1 — Los 5 patrones algorítmicos fundamentales

Los 5 patrones algorítmicos fundamentales
Los 5 patrones algorítmicos fundamentales

Definición

Un patrón algorítmico es una estructura de código reutilizable que resuelve una clase de problemas. Si aprendes a reconocer los patrones, puedes resolver problemas nuevos descomponiéndolos en patrones conocidos.

Los 5 patrones (los más usados)

Cómo reconocer un patrón

Cuando leas un problema, busca pistas en el enunciado:

  • "...calcular la suma de..." → Patrón 1
  • "...el promedio de..." → Patrón 2 (suma + conteo)
  • "...el número más grande de..." → Patrón 3
  • "...buscar un elemento que..." → Patrón 4
  • "...cuántos números cumplen..." → Patrón 5
Si el problema pide 2 o más cosas, es una combinación de patrones.
Cuaderno físico (obligatorio)

los 5 patrones con su "fórmula" en pseudocódigo. Memorízalos.

2.7.2 — Patrón 1: Suma (acumulador)

Patrón 1: Suma (acumulador)
Patrón 1: Suma (acumulador)

El patrón

suma = 0; // Inicialización (en 0)

for (/* cada elemento */) {

suma += elemento; // Acumulación

}

// Al final: 'suma' tiene la suma de todos los elementos

Ejemplo: suma de los primeros 100 naturales

int suma = 0;

for (int i = 1; i <= 100; i++) {

suma += i;

}

cout << "Suma: " << suma << endl;  // 5050

Diagrama de flujo clásico del patrón suma

┌─────────────┐

│ INICIO │ ⬭

└──────┬──────┘

│

▼

╱─────────────╲

║ suma = 0 ║ ▭ (inicialización)

╚═══════════════╝

│

▼

◆─────────────◆ ◇

╱ ╲

¿Hay más No ──────►

elementos? │

──────── │

│ │ │

Sí │ │ No │

▼ │ ▼

╔═════════════╗ ║ suma = ║ ▭ (salida)

║ LEER ║ ║ suma + x ║

║ elemento x ║ ╚══════╤════╝

╚══════╤══════╝ │

│ │

▼ │

╔═════════════╗ │

║ suma = ║ │

║ suma + x ║ │

╚══════╤══════╝ │

│ │

└────────┬────────┘

│

└──► (vuelve al rombo de "¿Hay más?")

Variantes del patrón

Suma con filtro: sumar SOLO los que cumplen condición.

int sumaPares = 0;

for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {  // Solo pares

sumaPares += i;

}

}

cout << "Suma de pares: " << sumaPares << endl;  // 2550

Suma hasta centinela:

int suma = 0, numero;

cout << "Números (0 para terminar):" << endl;
cin >> numero;  // Priming read
while (numero != 0) {

suma += numero;

cin >> numero;

}

cout << "Suma: " << suma << endl;

2.7.3 — Patrón 2: Promedio (suma + conteo)

Patrón 2: Promedio (suma + conteo)
Patrón 2: Promedio (suma + conteo)

El patrón

suma = 0;

contador = 0;

for (/* cada elemento */) {

suma += elemento;

contador++;

}

if (contador > 0) {
promedio = (double)suma / contador; // ⚠️ Cast a double para división decimal

}

// Al final: 'promedio' tiene el promedio, 'contador' tiene la cantidad

⚠️ El error #1: división entera

// ❌ MAL: división entera, resultado es 2 (no 2.5)

int suma = 5, contador = 2;

int promedio = suma / contador;

// ✅ BIEN: división decimal

double promedio = (double)suma / contador; // 2.5

Regla: SIEMPRE conviertes a double (o float) al menos UNO de los operandos antes de dividir.

Validación del divisor

if (contador > 0) {
promedio = (double)suma / contador;
} else {
cout << "No hay datos para promediar" << endl;

}

Si `contador == 0`, divides entre cero = crash.

Ejemplo: promedio de N calificaciones

int n;

double suma = 0, promedio;

int contador = 0;

cout << "¿Cuántas calificaciones? ";
cin >> n;
for (int i = 1; i <= n; i++) {

double cal;

cout << "Calificación " << i << ": ";
cin >> cal;
if (cal >= 0 && cal <= 10) {  // Validar

suma += cal;

contador++;

}

}

if (contador > 0) {
promedio = suma / contador;
cout << "Promedio: " << promedio << endl;
} else {
cout << "No hay calificaciones válidas" << endl;

}

2.7.4 — Patrón 3: Mayor/menor (algoritmo del centinela)

Patrón 3: Mayor/menor (centinela)
Patrón 3: Mayor/menor (centinela)

El patrón

// Inicialización: el primer elemento es "candidato" a mayor

mayor = secuencia[0]; // O el primero que leas

for (/* cada elemento */) {
if (elemento > mayor) {

mayor = elemento; // Actualizar el candidato

}

}

// Al final: 'mayor' es el elemento más grande

La clave: inicializar con el PRIMER elemento

// ❌ MAL: inicializar en 0 falla si todos los números son negativos

int mayor = 0;

int nums[] = {-5, -3, -10, -1};

// Resultado: 0 (incorrecto, debería ser -1)

// ✅ BIEN: inicializar con el primer elemento

int mayor = nums[0]; // -5

// Iteración: -5 > -5? No. -3 > -5? Sí → mayor = -3

// -10 > -3? No. -1 > -3? Sí → mayor = -1 ✓

Variante: encontrar menor

menor = secuencia[0];

for (/* ... */) {
if (elemento < menor) {

menor = elemento;

}

}

Variante: encontrar la posición del mayor

int mayorPos = 0;

for (int i = 1; i < n; i++) {
if (arreglo[i] > arreglo[mayorPos]) {

mayorPos = i;

}

}

cout << "Mayor: " << arreglo[mayorPos] << " en posición " << mayorPos << endl;

Ejemplo: mayor de N números ingresados por el usuario

int n, numero, mayor;

cout << "¿Cuántos números? ";
cin >> n;
cout << "Número 1: ";
cin >> numero;

mayor = numero; // Inicializar con el primero

for (int i = 2; i <= n; i++) {
cout << "Número " << i << ": ";
cin >> numero;
if (numero > mayor) {

mayor = numero;

}

}

cout << "El mayor es: " << mayor << endl;

Diagrama de flujo del patrón mayor

┌─────────────┐

│ INICIO │ ⬭

└──────┬──────┘

│

▼

╱───────────────╲

║ LEER primero ║ ▱

║ mayor = x ║

╚════════╤════════╝

│

▼

◆─────────────◆ ◇

╱ ╲

¿Hay más No ──────►

elementos? │ ╔══════════╗

──────── │ ║ ESCRIBIR ║ ▱

│ │ │ ║ mayor ║

Sí │ │ No │ ╚══════════╝

▼ │ ▲

╔═══════════╗ │

║ LEER x ║ ▱ │

╚═════╤═════╝ │

│ │

▼ │

╔═══════════════╗ │

║ ¿x > mayor? ║ ◇ │

╚══╤═════════╤══╝ │

│ Sí │ No │

▼ │ │

╔══════════╗ │ │

║ mayor = x ║ ▭ │

╚══╤═══════╝ │ │

└────┬────┘ │

│ │

└────► (vuelve a "¿Hay más?")

Cuaderno físico (obligatorio)

el patrón mayor/menor. Memorízalo: inicializa con el primer elemento, no con 0.

2.7.5 — Patrón 4: Búsqueda (lineal con bandera)

Patrón 4: Búsqueda (lineal con bandera)
Patrón 4: Búsqueda (lineal con bandera)

El patrón

posicion = -1; // Bandera: -1 significa "no encontrado"

for (/* cada elemento */) {
if (elemento == objetivo) {

posicion = i; // ¡Encontrado!

break; // Salir del bucle

}

}

// Verificar la bandera

if (posicion != -1) {
cout << "Encontrado en posición " << posicion << endl;
} else {
cout << "No encontrado" << endl;

}

La clave: la bandera (flag)

La variable posicion (o encontrado, o bool encontrado) funciona como centinela lógica: si vale -1 (o false), no se encontró; si vale otra cosa (o true), se encontró.

Búsqueda con while y centinela

int numero, objetivo;

bool encontrado = false;

cout << "Número a buscar: "; cin >> objetivo;
cout << "Ingresa números (0 para terminar):" << endl;
cin >> numero;  // Priming read
while (numero != 0 && !encontrado) {
if (numero == objetivo) {

encontrado = true;

} else {
cin >> numero;

}

}

cout << (encontrado ? "Encontrado" : "No encontrado") << endl;

Búsqueda con for y break

int nums[] = {10, 25, 7, 40, 15};

int objetivo = 7;

int posicion = -1;

for (int i = 0; i < 5; i++) {
if (nums[i] == objetivo) {

posicion = i;

break; // Salir al encontrar

}

}

if (posicion != -1) {
cout << "Encontrado en posición " << posicion << endl;

}

2.7.6 — Patrón 5: Conteo por condición (filtro)

Patrón 5: Conteo por condición (filtro)
Patrón 5: Conteo por condición (filtro)

El patrón

contador = 0;

for (/* cada elemento */) {
if (/* condición de filtro */) {

contador++; // Solo contar los que cumplen

}

}

Ejemplo: contar positivos, negativos y ceros

int nums[] = {5, -3, 0, 8, -1, 0, 12, -7};

int positivos = 0, negativos = 0, ceros = 0;

for (int i = 0; i < 8; i++) {
if (nums[i] > 0) positivos++;
else if (nums[i] < 0) negativos++;

else ceros++;

}

cout << "Positivos: " << positivos << endl;  // 3
cout << "Negativos: " << negativos << endl;  // 3
cout << "Ceros: " << ceros << endl;           // 2

Variante: con entrada del usuario y centinela

int positivos = 0, negativos = 0, numero;

cout << "Números (0 para terminar):" << endl;
cin >> numero;
while (numero != 0) {
if (numero > 0) positivos++;
else if (numero < 0) negativos++;
cin >> numero;

}

cout << "Positivos: " << positivos << endl;
cout << "Negativos: " << negativos << endl;

2.7.7 — Combinación de patrones

Por qué combinar

Los problemas reales casi nunca son UN solo patrón. Suelen ser combinaciones:

Ejemplo: "Suma de los pares y promedio de los impares"

int n, numero;

int sumaPares = 0, sumaImpares = 0, contadorImpares = 0;

cout << "¿Cuántos números? "; cin >> n;
for (int i = 1; i <= n; i++) {
cout << "Número " << i << ": ";
cin >> numero;
if (numero % 2 == 0) {

sumaPares += numero; // Patrón suma + filtro

} else {

sumaImpares += numero; // Patrón suma

contadorImpares++; // Patrón conteo

}

}

cout << "Suma de pares: " << sumaPares << endl;
if (contadorImpares > 0) {

double promedioImpares = (double)sumaImpares / contadorImpares;

cout << "Promedio de impares: " << promedioImpares << endl;
} else {
cout << "No hay impares" << endl;

}

Cuaderno físico (obligatorio)

3 combinaciones de patrones con problemas de tu vida real. Descompón cada uno en los patrones básicos.

2.7.8 — Patrones en entrevistas: los 10 problemas más comunes

Los 10 problemas algorítmicos más frecuentes en entrevistas junior

Basado en análisis de entrevistas técnicas en México y EE.UU. para vacantes junior:

Plantilla para resolver CUALQUIER problema algorítmico

  1. Lee el problema 3 veces.
  2. Identifica:
  • ¿Qué me piden? (suma, mayor, búsqueda, etc.)
  • ¿Qué datos tengo? (entrada)
  • ¿Qué quiero obtener? (salida)
  1. Identifica el PATRÓN o patrones.
  2. Escribe el pseudocódigo a mano.
  3. Traza con 2-3 datos de prueba.
  4. Codifica.
  5. Ejecuta con los mismos datos y compara.
Cuaderno físico (obligatorio)

los 10 problemas algorítmicos más comunes en entrevistas. Practica cada uno en tu cuaderno antes de codearlo.

🤖 IA como copiloto — 🤖 AI Mission 2.7

Prompt 1: "Te voy a pegar un problema algorítmico. NO me des la solución. Solo dime: (1) qué patrón(es) usa, (2) qué variables clave necesito, (3) cuál sería la estructura del bucle. Máximo 150 palabras."

Prompt 2: "Necesito resolver el problema 'suma de los múltiplos de 3 entre 1 y 100'. Dame el código en C++ usando el patrón suma + filtro. Explícame paso a paso. Máximo 200 palabras."

Prompt 3: "Te voy a pegar mi implementación del patrón mayor/menor. NO me corrijas. Solo dime: (1) si inicializo correctamente la variable mayor, (2) si hay un caso borde que no estoy manejando, (3) si el bucle es eficiente. Máximo 150 palabras."

🧪 Laboratorio — 🧪 LAB 2.7 — 7 ejercicios de patrones

🛠️ Herramienta recomendada para los diagramas de flujo de este LAB: Para los ejercicios que pidan un diagrama de flujo, usa [draw.io (diagrams.net)](https://app.diagrams.net/) — herramienta gratis, sin registro, que funciona en el navegador. Tiene plantillas con la simbología ANSI/ISO lista (en `General → Flowchart`). Exporta tus diagramas como PNG e insértalos en tu cuaderno digital o entrégalos junto con el código. Otras opciones libres: - [Mermaid](https://mermaid.live/) — diagramas desde código Markdown. Ideal para Git. - [Excalidraw](https://excalidraw.com/) — estilo "dibujado a mano", muy intuitivo. - Dibujar a mano en tu cuaderno — siempre válido, especialmente para trazar el razonamiento.

Ejercicio 1 — Suma de los primeros N naturales (básico, 10 min)

Enunciado. Pide N al usuario y calcula la suma de los primeros N naturales (1+2+3+...+N) usando for.

Criterio de éxito: con N=100, suma=5050.

Rúbrica (10 pts): bucle correcto (5 pts) + cálculo (3 pts) + verificación (2 pts).

Ejercicio 2 — Promedio con validación (básico, 15 min)

Enunciado. Pide 5 calificaciones al usuario. Calcula el promedio, pero solo de las válidas (entre 0 y 10). Si no hay ninguna válida, muestra "No hay calificaciones".

Rúbrica (10 pts): bucle (3 pts) + validación (4 pts) + promedio (3 pts).

Ejercicio 3 — Mayor y menor (básico, 15 min)

Enunciado. Pide N al usuario, luego N números. Encuentra y muestra el mayor y el menor. No inicialices con 0, usa el primer número como referencia.

Criterio de éxito: con N=5 y nums {3, 7, 2, 9, 5}, mayor=9, menor=2.

Rúbrica (10 pts): mayor (3 pts) + menor (3 pts) + inicialización correcta (4 pts).

Ejercicio 4 — Conteo por condición (intermedio, 20 min)

Enunciado. Pide N al usuario y luego N números. Cuenta cuántos son positivos, negativos, pares, y múltiplos de 5. Muestra los 4 contadores.

Criterio de éxito: con N=10 y nums {-3, 5, 8, 10, -7, 0, 15, 2, 20, -1}, positivos=6, negativos=3, pares=5, múltiplos de 5=4.

Rúbrica (10 pts): 4 contadores × 2 pts + bucle correcto (2 pts).

Ejercicio 5 — Búsqueda con bandera (intermedio, 25 min)

Enunciado. Pide N, luego N números, luego un número a buscar. Di si está y en qué posición. Usa el patrón de búsqueda con bandera. Si NO está, muestra "No encontrado".

Criterio de éxito: con nums {10, 25, 7, 40, 15} y objetivo 7, debe decir "Posición 2".

Rúbrica (10 pts): bucle (3 pts) + bandera (3 pts) + mensaje correcto (4 pts).

Ejercicio 6 — Combinación suma + filtro + mayor (avanzado, 30 min)

Enunciado. Pide N calificaciones. Calcula: suma total, cantidad de aprobados (>= 7), promedio de los aprobados, y la calificación mayor entre los aprobados. Si no hay aprobados, muestra "No hay aprobados".

Rúbrica (10 pts): suma (2 pts) + filtro (2 pts) + promedio (3 pts) + mayor (3 pts).

Ejercicio 7 — FizzBuzz clásico de entrevistas (avanzado, 30 min)

Enunciado. Imprime los números del 1 al 100, pero:

  • Si el número es múltiplo de 3, imprime "Fizz".
  • Si es múltiplo de 5, imprime "Buzz".
  • Si es múltiplo de ambos (3 y 5), imprime "FizzBuzz".
  • En otros casos, imprime el número.

Criterio de éxito: la salida sigue el patrón FizzBuzz correctamente.

Rúbrica (10 pts): bucle (2 pts) + condiciones correctas (4 pts) + orden de las condiciones (2 pts) + output (2 pts).

Ejercicio bonus — Números perfectos (opcional, 30 min)

Enunciado. Un número es perfecto si la suma de sus divisores propios (excluyendo al número) es igual al número. Ejemplo: 6 = 1+2+3. Pide N y di si es perfecto, mostrando sus divisores.

Rúbrica bonus (5 pts): algoritmo (3 pts) + output (2 pts).

🎯 Cierre del tema

Lo que aprendiste hoy:

  • Los 5 patrones algorítmicos fundamentales: suma, promedio, mayor/menor, búsqueda, conteo.
  • Cómo combinar patrones para problemas complejos.
  • Los 10 problemas algorítmicos más comunes en entrevistas junior.
  • La plantilla para resolver cualquier problema algorítmico.

Lo que sigue: en el Tema 2.8 — Testing: Pruebas de Escritorio y `assert` (6h), vas a aprender a verificar que tu código funciona correctamente sin tener que ejecutarlo mentalmente. Es la base del testing profesional: una habilidad que te separa de un junior "que programa" de un junior "que programa confiablemente".

XP obtenida al completar este tema: 100 base + 30 por LAB (7 ejercicios) + 20 por Quest = 150 XP.

*"Un junior que domina los 5 patrones resuelve el 80% de los problemas. Un senior los combina con otros patrones para el otro 20%."* — De la introducción de este manual.

Fin del Tema 2.7

📝 Quest · Cuestionario — 📝 Quest — Reactivos para autoevaluación

Las siguientes preguntas te sirven para autoevaluarte después de leer el tema. Responde en tu cuaderno o mentalmente, y luego revisa las Respuestas modelo (disponibles en libre acceso, sin iniciar sesión).

Sección A · Opción múltiple

Elige la opción correcta (A, B, C o D). Las respuestas están en la sección Respuestas modelo.

  1. ¿Qué es un contador?
    • Una variable que cuenta ocurrencias
    • Un bucle
    • Una función
    • Un array
  2. Patrón clásico de contador en C++:
    • ++x
    • contador++ o contador = contador + 1
    • contador += 2
    • contador = 0
  3. ¿Qué es un acumulador?
    • Una batería
    • Variable que suma valores progresivamente
    • Un bucle
    • Una constante
  4. Diferencia entre contador y acumulador:
    • Son iguales
    • Contador += 1; acumulador += valor variable
    • Acumulador no existe
    • Contador no existe
  5. ¿Qué es un centinela (sentinel)?
    • Un valor especial que marca fin de datos
    • Un error
    • Un tipo de variable
    • Un bucle
  6. ¿Cómo se lee una serie de números hasta -1?
    • for(;;)
    • while (n != -1) { ... }
    • if
    • switch
  7. Ejemplo de acumulador en suma:
    • i++
    • suma = suma + nota
    • for
    • if
  8. Para calcular un promedio, ¿qué patrón se usa?
    • Solo contador
    • Acumulador + contador: promedio = suma / n
    • Solo acumulador
    • switch
  9. Una serie de números termina con 0. ¿Qué patrón es?
    • Contador
    • Centinela (0 marca fin)
    • Acumulador
    • for infinito
  10. Patrón max-min en una serie:
    • Solo acumulador
    • Actualizar max/min al leer cada número
    • Centinela
    • for

Sección B · Preguntas abiertas

Desarrolla tu respuesta en al menos 3 líneas. Compara con la respuesta modelo después de escribir.

  1. Diseña un algoritmo que cuente cuántos números positivos, negativos y ceros hay en un arreglo de n elementos.
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
  2. ¿Cómo calcularías el promedio de una serie de números usando contador y acumulador?
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
  3. Explica el patrón centinela con un ejemplo de validación de entrada de usuario.
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…

🟢 Cuando termines, revisa las Respuestas modelo y compáralas con las tuyas. La mejor forma de aprender es discutir cada respuesta contigo mismo o con un compañero.

← Volver a temas del capítulo 📚 Ver todos los temas 🔑 Inicia sesión para hacer el Test