Estructuras de Datos y Proyecto Final

3.04 · Arreglos Bidimensionales (Matrices)

PF-304 ⏱ 90 min ⭐ 120 XP intermedio

🧠 Teoría y conceptos — 🟦 1. ¿Qué es una matriz?

Arreglos bidimensionales: declaración y acceso
Arreglos bidimensionales: declaración y acceso

Figura: Matriz 3x4 con índices y valores

Una matriz es un arreglo de arreglos:

// Matriz de 3 filas x 4 columnas

int matriz[3][4] = {

{1, 2, 3, 4},     // fila 0
{5, 6, 7, 8},     // fila 1
{9, 10, 11, 12}   // fila 2

};

cout << matriz[1][2] << endl;  // 7 (fila 1, columna 2)

Acceso: [fila][columna]

matriz[0][0] = 1; // esquina superior izquierda

matriz[0][3] = 4; // esquina superior derecha

matriz[2][0] = 9; // esquina inferior izquierda

matriz[2][3] = 12; // esquina inferior derecha

⚠️ Trampa mental: orden de índices

matriz[fila][columna] — la fila primero. Es como notación matemática: a_{i,j} donde i es fila y j es columna. Si los volteas, accedes a otro elemento (o fuera de rango).

🧠 2. Cómo se guarda en memoria

Recorrido de matrices
Recorrido de matrices

Concepto clave: una matriz es lineal en memoria. El compilador la guarda fila por fila:

Índice lineal: 0 1 2 3 4 5 6 7 8 9 10 11

Valor: 1 2 3 4 5 6 7 8 9 10 11 12

└─ fila 0 ─┘└─ fila 1 ─┘└─ fila 2 ─┘

Fórmula: matriz[i][j] está en la posición lineal i * numColumnas + j.

int matriz[3][4];

// matriz[1][2] = posición 1*4 + 2 = 6

¿Por qué importa esto? Porque cuando recorres mal la matriz (por columnas en vez de filas), el patrón de acceso a memoria es ineficiente — la CPU "salta" y tarda más. No lo vas a notar con 12 elementos; con una imagen de 1920×1080 sí.

📏 3. Inicialización

Operaciones con matrices
Operaciones con matrices

Completa con valores

int matriz[2][3] = {{1, 2, 3}, {4, 5, 6}};

Con ceros

int matriz[3][3] = {};  // todo en 0
int matriz[3][3] = {0}; // también

Sin valores específicos (c++11+)

int matriz[3][3] = {{1, 2}, {4}};  // completa con 0
// {{1, 2, 0}, {4, 0, 0}, {0, 0, 0}}

Tamaño variable con constantes

const int FILAS = 3;

const int COLS = 4;

int matriz[FILAS][COLS];

Regla: usa `const int` para tamaños. Te protege de typos y el compilador puede optimizar.

🔄 4. Recorrido: por filas vs por columnas

Aplicaciones de matrices
Aplicaciones de matrices

Por filas (patrón recomendado en C++)

Figura: Recorrido por filas

int m[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
for (int i = 0; i < 3; i++) {        // filas
for (int j = 0; j < 4; j++) {    // columnas
cout << m[i][j] << "\t";

}

cout << endl;

}

Salida: 1 2 3 4 / 5 6 7 8 / 9 10 11 12 — una fila por línea.

Por columnas

Figura: Recorrido por columnas

for (int j = 0; j < 4; j++) {        // columnas primero
for (int i = 0; i < 3; i++) {    // filas
cout << m[i][j] << "\t";

}

cout << endl;

}

Salida: 1 5 9 / 2 6 10 / 3 7 11 / 4 8 12 — una columna por línea.

Lección: con matrices pequeñas ambas funcionan. Con matrices grandes, recorre por filas (es el orden natural de la memoria en C++).

➕ 5. Operaciones básicas

Patrones comunes con matrices
Patrones comunes con matrices

Suma de todos los elementos

int suma = 0;

for (int i = 0; i < FILAS; i++) {
for (int j = 0; j < COLS; j++) {

suma += matriz[i][j];

}

}

Suma por fila

for (int i = 0; i < FILAS; i++) {

int sumaFila = 0;

for (int j = 0; j < COLS; j++) {

sumaFila += matriz[i][j];

}

cout << "Suma fila " << i << ": " << sumaFila << endl;

}

Suma por columna

for (int j = 0; j < COLS; j++) {

int sumaCol = 0;

for (int i = 0; i < FILAS; i++) {

sumaCol += matriz[i][j];

}

cout << "Suma col " << j << ": " << sumaCol << endl;

}

🔁 6. Transpuesta

Errores típicos con matrices
Errores típicos con matrices

La transpuesta intercambia filas por columnas: B[i][j] = A[j][i].

int A[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};

int B[4][3];

for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {

B[j][i] = A[i][j]; // índices invertidos

}

}

// B es de 4x3 ahora

Verificación: la fila 0 de A (1 2 3 4) se convierte en la columna 0 de B.

🔍 7. Búsqueda en matriz

Problema: encontrar un valor y reportar su posición.

Figura: Acceso a un elemento específico

int buscar(int matriz[][MAX_COLS], int filas, int cols, int objetivo) {

for (int i = 0; i < filas; i++) {
for (int j = 0; j < cols; j++) {
if (matriz[i][j] == objetivo) {
cout << "Encontrado en [" << i << "][" << j << "]" << endl;
return 1;  // encontrado

}

}

}

return 0;  // no encontrado

}

Nota: en la firma, la segunda dimensión debe tener tamaño. El compilador la necesita para calcular el offset.

🏆 8. Ejemplo aplicado: calificaciones

Figura: Matriz de calificaciones por alumno y materia

const int ALUMNOS = 4;

const int MATERIAS = 3;

// cal[alumno][materia]

float cal[ALUMNOS][MATERIAS] = {

{8.5, 9.0, 7.5},   // Alumno 0
{6.0, 7.5, 8.0},   // Alumno 1
{9.5, 8.5, 9.0},   // Alumno 2
{7.0, 8.0, 6.5}    // Alumno 3

};

// Promedio por alumno

for (int i = 0; i < ALUMNOS; i++) {

float suma = 0;

for (int j = 0; j < MATERIAS; j++) suma += cal[i][j];
cout << "Alumno " << i << " promedio: " << suma/MATERIAS << endl;

}

// Promedio por materia

for (int j = 0; j < MATERIAS; j++) {

float suma = 0;

for (int i = 0; i < ALUMNOS; i++) suma += cal[i][j];
cout << "Materia " << j << " promedio: " << suma/ALUMNOS << endl;

}

🔲 9. Caso especial: matriz identidad

Figura: Matriz identidad 4x4

La matriz identidad tiene 1 en la diagonal y 0 en el resto. Es el "1" de la multiplicación de matrices: A × I = A.

const int N = 4;

int I[N][N] = {};
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {

I[i][j] = (i == j) ? 1 : 0;

}

}

Salida:

1 0 0 0

0 1 0 0

0 0 1 0

0 0 0 1

🧪 12. LAB 3.4 — Sistema de Calificaciones con Matriz (4 h)

Descripción

Crea un programa que gestione las calificaciones de 5 alumnos en 4 materias:

  1. Captura la matriz de calificaciones (valida que estén entre 0 y 10).
  2. Calcula e imprime:
  • Promedio por alumno (con su estado: aprobado ≥ 6, reprobado < 6).
  • Promedio por materia.
  • Promedio general del grupo.
  1. Encuentra al alumno con el mejor promedio y al de peor promedio.
  2. Genera la transpuesta de la matriz y muéstrala (materias como filas, alumnos como columnas).
  3. Búsqueda: pide una calificación al usuario y muestra en qué posiciones aparece.

Rúbrica de evaluación

Bonus XP

  • +30 XP si usas struct Alumno { string nombre; float calificaciones[4]; } para que cada alumno tenga nombre.
  • +20 XP si la búsqueda muestra el nombre del alumno, no solo el índice.
  • +20 XP si generas un histograma en consola del rendimiento del grupo (cuántos sacaron 0-5, 6-7, 8-9, 10).

🔚 14. Cierre — Cuaderno del programador

  1. Dibuja la matriz 4×5 del LAB. Escribe la fórmula para la posición lineal de cada elemento (i, j).
  2. Reflexiona: ¿por qué el IPN (y la mayoría de planes de estudio) enseña primero arreglos 1D y luego 2D? ¿Qué analogía de la vida real sustenta esta progresión?
  3. Anota una pregunta que aún tengas sobre matrices. Compártela con tu grupo o con la IA — pero primero formula tu propia hipótesis.

🏅 Insignia y XP del tema

🔗 ¿Qué sigue?

Tema 3.5 — Búsqueda: Secuencial vs Binaria. Dos algoritmos para el mismo problema (encontrar un elemento): uno vale para todo, el otro es ridículamente más rápido pero requiere datos ordenados. Aquí el Big O se vuelve tangible: verás la diferencia en tiempo real.

Antes de avanzar:

  • [ ] LAB 3.4 entregado y funcionando
  • [ ] Quest mixto respondido en el cuaderno
  • [ ] Reflexión escrita

*"Una matriz no es una tabla. Es memoria lineal que tu cerebro lee en 2D. Entender eso es entender la computación."*

⚠️ Errores típicos — ⚠️ 11. Errores típicos del razonamiento

Error 1: Confundir [i][j] con [j][i]

cout << matriz[2][1] << endl;  // fila 2, columna 1
cout << matriz[1][2] << endl;  // fila 1, columna 2

// Son elementos DIFERENTES

Aclaración: si matriz[2][1] = 8, entonces matriz[1][2] puede ser cualquier otra cosa.

Error 2: Olvidar el tamaño de la segunda dimensión en funciones

void imprimir(int m[][]) { ... }       // ERROR de compilación
void imprimir(int m[][10]) { ... }     // BIEN

El compilador necesita saber el ancho de columna para calcular la posición en memoria.

Error 3: Índices fuera de rango

int m[3][4];

cout << m[3][0] << endl;  // fila 3 NO EXISTE (válidas: 0, 1, 2)
cout << m[0][4] << endl;  // columna 4 NO EXISTE (válidas: 0, 1, 2, 3)

Compila y ejecuta, pero lee/escribe basura o crashea. Aprende a contar desde 0.

Error 4: Recorrer con <= en vez de <

for (int i = 0; i <= 3; i++) { ... }  // i vale 0, 1, 2, 3 → fuera de rango en [3][?]

Siempre `<`, nunca <=, a menos que sepas exactamente por qué.

Error 5: Asumir que toda matriz es cuadrada

int A[3][3];

int B[3][3];

int C[3][4] = A; // ERROR: no se puede asignar matrices en C++

No existe asignación directa de matrices en C++. Debes copiar elemento por elemento con un loop.

🤖 IA como copiloto — 🤖 10. AI Mission — "Genera la operación, no el LAB"

Objetivo: usar la IA para operaciones mecánicas, no para la lógica central.

Escenario: tienes una matriz 4×4 y necesitas la traza (suma de la diagonal principal).

Prompt sugerido:

"Dame una función en C++ que calcule la traza de una matriz cuadrada NxN. La función debe recibir la matriz y N, y retornar un `long long`. Incluye un ejemplo de uso con una matriz 4x4."

Lo que NO debes hacer:

  • Pedirle que resuelva el LAB 3.4.
  • Aceptar el código sin trazarlo: ejecútalo con 3 matrices y verifica.

Lo que SÍ debes hacer:

  • Escribir primero la fórmula mental: traza = m[0][0] + m[1][1] + m[2][2] + m[3][3].
  • Comparar tu versión con la de la IA: ¿cuál es más clara?

Ritual de 3 min: si la IA te da una versión que no entiendes, pídele que te la explique con una analogía, no que te dé otra versión.

📝 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. ¿Cómo se declara una matriz 3x4 en C++?
    • int m[3,4];
    • int m[3][4];
    • matrix m(3,4);
    • int m(3)(4);
  2. ¿Cómo acceder al elemento fila 2 columna 3?
    • m(2,3)
    • m[1][2]
    • m[2][3]
    • m{2}{3}
  3. ¿Cómo se recorre una matriz 2D?
    • Un for
    • Dos for anidados (filas, columnas)
    • Un while
    • Un switch
  4. ¿Qué es una matriz triangular?
    • Cuadrada
    • Solo tiene valores en o por encima/debajo de la diagonal
    • 1x1
    • Vacía
  5. Para una matriz de 3x3, ¿cuántos elementos tiene?
    • 6
    • 9
    • 3
    • 12
  6. ¿Cómo se inicializa una matriz?
    • int m[2][3] = {{1,2,3},{4,5,6}};
    • int m[2,3] = 1,2,3,4,5,6;
    • m = [[1,2,3],[4,5,6]]
    • Solo en tiempo de ejecución
  7. ¿Qué representa la diagonal principal de una matriz?
    • m[0][0], m[0][1]...
    • m[0][0], m[1][1], m[2][2]...
    • Solo m[0][0]
    • La última fila
  8. ¿Cómo sumar dos matrices?
    • m1 + m2
    • Bucles anidados: resultado[i][j] = m1[i][j] + m2[i][j]
    • Solo en una función
    • No se puede
  9. ¿Qué es una matriz identidad?
    • Todos 0
    • 1s en la diagonal, 0s en el resto
    • Todos 1s
    • Aleatoria
  10. ¿Cómo se pasa una matriz a una función?
    • Como valor
    • Con declaración del tamaño: void f(int m[][MAX])
    • No se puede
    • Solo puntero

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 encuentre el número más grande de una matriz 3x3 y su posición.
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
  2. ¿Cómo sumarías dos matrices? Escribe el pseudocódigo.
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
  3. Explica la diferencia entre una matriz y un vector de vectores. ¿Cuándo usar cada uno?
    → 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