Arrays multidimensionales
Los arrays multidimensionales representan una extensión natural de los arrays unidimensionales, permitiendo organizar los datos en estructuras rectangulares de múltiples dimensiones. Estas estructuras son especialmente útiles para representar información que se organiza naturalmente en filas y columnas, como matrices matemáticas, tablas de datos o grids de juegos.
En C#, los arrays multidimensionales proporcionan una forma eficiente de manejar datos tabulares manteniendo la ventaja de acceso directo por índices. A diferencia de los arrays de arrays (también llamados arrays dentados), los arrays multidimensionales garantizan una estructura rectangular donde todas las filas tienen exactamente el mismo número de columnas.
En este artículo exploraremos cómo declarar, inicializar y manipular arrays multidimensionales, así como sus aplicaciones prácticas más comunes.
Conceptos fundamentales
Un array multidimensional es una estructura de datos que organiza elementos en múltiples dimensiones, formando una matriz rectangular. En C#, el tipo más común es el array bidimensional (dos dimensiones), aunque el lenguaje soporta arrays de cualquier número de dimensiones.
Características principales de los arrays multidimensionales
Característica | Descripción |
---|---|
Estructura rectangular | Todas las filas tienen el mismo número de columnas |
Acceso por índices | Se accede usando array[fila, columna] |
Tipo homogéneo | Todos los elementos son del mismo tipo |
Tamaño fijo | Las dimensiones se establecen en tiempo de creación |
Almacenamiento contiguo | Los elementos se almacenan de forma contigua en memoria |
Diferencias con arrays de arrays
Es importante distinguir entre arrays multidimensionales y arrays de arrays:
Arrays multidimensionales | Arrays de arrays (jagged arrays) |
---|---|
int[,] matriz = new int[3,4] |
int[][] matriz = new int[3][] |
Estructura rectangular obligatoria | Cada fila puede tener diferente longitud |
Sintaxis: matriz[i,j] |
Sintaxis: matriz[i][j] |
Un solo objeto en memoria | Múltiples objetos array |
Declaración y inicialización
Declaración básica
La sintaxis para declarar un array multidimensional utiliza comas dentro de los corchetes para indicar las dimensiones:
// Declaración de un array bidimensional (matriz)
int[,] matriz;
// Declaración de un array tridimensional
int[,,] cubo;
// Declaración con inicialización de tamaño
int[,] tablero = new int[8, 8]; // 8 filas, 8 columnas
Inicialización con valores
Podemos inicializar arrays multidimensionales de varias formas:
using System;
class Program
{
static void Main()
{
// Inicialización con valores literales
int[,] numeros = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Inicialización explícita con new
int[,] matriz = new int[,] {
{10, 20, 30},
{40, 50, 60}
};
// Inicialización con tamaño específico
string[,] nombres = new string[2, 3];
nombres[0, 0] = "Ana";
nombres[0, 1] = "Luis";
nombres[0, 2] = "María";
nombres[1, 0] = "Carlos";
nombres[1, 1] = "Elena";
nombres[1, 2] = "Jorge";
// Mostrar el contenido de la primera matriz
Console.WriteLine("Contenido de la matriz de números:");
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Console.Write($"{numeros[i, j]} ");
}
Console.WriteLine();
}
}
}
Inicialización dinámica
También podemos inicializar arrays multidimensionales basándonos en entrada del usuario o cálculos:
using System;
class Program
{
static void Main()
{
Console.Write("Introduce el número de filas: ");
int filas = int.Parse(Console.ReadLine());
Console.Write("Introduce el número de columnas: ");
int columnas = int.Parse(Console.ReadLine());
// Crear array con dimensiones dinámicas
int[,] matriz = new int[filas, columnas];
// Llenar con valores calculados
for (int i = 0; i < filas; i++)
{
for (int j = 0; j < columnas; j++)
{
matriz[i, j] = (i + 1) * (j + 1);
}
}
// Mostrar la matriz resultado
Console.WriteLine("\nMatriz generada:");
MostrarMatriz(matriz);
}
static void MostrarMatriz(int[,] matriz)
{
int filas = matriz.GetLength(0);
int columnas = matriz.GetLength(1);
for (int i = 0; i < filas; i++)
{
for (int j = 0; j < columnas; j++)
{
Console.Write($"{matriz[i, j]:D3} ");
}
Console.WriteLine();
}
}
}
Acceso y manipulación de elementos
Propiedades importantes
Los arrays multidimensionales proporcionan métodos específicos para obtener información sobre sus dimensiones:
Propiedad/Método | Descripción | Ejemplo |
---|---|---|
Length |
Total de elementos | matriz.Length |
GetLength(dimension) |
Longitud de una dimensión específica | matriz.GetLength(0) (filas) |
Rank |
Número de dimensiones | matriz.Rank |
Ejemplo práctico: tabla de multiplicar
using System;
class Program
{
static void Main()
{
// Crear una tabla de multiplicar 10x10
int[,] tablaMultiplicar = new int[11, 11]; // 0 a 10
// Llenar la tabla
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j <= 10; j++)
{
tablaMultiplicar[i, j] = i * j;
}
}
// Mostrar información de la tabla
Console.WriteLine($"La tabla tiene {tablaMultiplicar.Rank} dimensiones");
Console.WriteLine($"Filas: {tablaMultiplicar.GetLength(0)}");
Console.WriteLine($"Columnas: {tablaMultiplicar.GetLength(1)}");
Console.WriteLine($"Total de elementos: {tablaMultiplicar.Length}");
// Mostrar parte de la tabla (5x5)
Console.WriteLine("\nPrimeras 5x5 posiciones de la tabla:");
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 5; j++)
{
Console.Write($"{tablaMultiplicar[i, j]:D2} ");
}
Console.WriteLine();
}
// Búsqueda de un valor específico
int valorBuscado = 24;
EncontrarValor(tablaMultiplicar, valorBuscado);
}
static void EncontrarValor(int[,] matriz, int valor)
{
bool encontrado = false;
for (int i = 0; i < matriz.GetLength(0) && !encontrado; i++)
{
for (int j = 0; j < matriz.GetLength(1); j++)
{
if (matriz[i, j] == valor)
{
Console.WriteLine($"\nValor {valor} encontrado en posición [{i}, {j}]");
Console.WriteLine($"Esto representa: {i} × {j} = {valor}");
encontrado = true;
break;
}
}
}
if (!encontrado)
{
Console.WriteLine($"\nValor {valor} no encontrado en la tabla");
}
}
}
Operaciones comunes con arrays multidimensionales
Suma de matrices
using System;
class Program
{
static void Main()
{
int[,] matrizA = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int[,] matrizB = {
{9, 8, 7},
{6, 5, 4},
{3, 2, 1}
};
int[,] resultado = SumarMatrices(matrizA, matrizB);
Console.WriteLine("Matriz A:");
MostrarMatriz(matrizA);
Console.WriteLine("\nMatriz B:");
MostrarMatriz(matrizB);
Console.WriteLine("\nMatriz A + B:");
MostrarMatriz(resultado);
}
static int[,] SumarMatrices(int[,] a, int[,] b)
{
// Verificar que las matrices tengan las mismas dimensiones
if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1))
{
throw new ArgumentException("Las matrices deben tener las mismas dimensiones");
}
int filas = a.GetLength(0);
int columnas = a.GetLength(1);
int[,] resultado = new int[filas, columnas];
for (int i = 0; i < filas; i++)
{
for (int j = 0; j < columnas; j++)
{
resultado[i, j] = a[i, j] + b[i, j];
}
}
return resultado;
}
static void MostrarMatriz(int[,] matriz)
{
int filas = matriz.GetLength(0);
int columnas = matriz.GetLength(1);
for (int i = 0; i < filas; i++)
{
for (int j = 0; j < columnas; j++)
{
Console.Write($"{matriz[i, j]:D2} ");
}
Console.WriteLine();
}
}
}
Transposición de matriz
using System;
class Program
{
static void Main()
{
int[,] original = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int[,] transpuesta = TransponerMatriz(original);
Console.WriteLine("Matriz original (3x4):");
MostrarMatriz(original);
Console.WriteLine("\nMatriz transpuesta (4x3):");
MostrarMatriz(transpuesta);
}
static int[,] TransponerMatriz(int[,] matriz)
{
int filas = matriz.GetLength(0);
int columnas = matriz.GetLength(1);
// La transpuesta tiene las dimensiones invertidas
int[,] transpuesta = new int[columnas, filas];
for (int i = 0; i < filas; i++)
{
for (int j = 0; j < columnas; j++)
{
transpuesta[j, i] = matriz[i, j];
}
}
return transpuesta;
}
static void MostrarMatriz(int[,] matriz)
{
int filas = matriz.GetLength(0);
int columnas = matriz.GetLength(1);
for (int i = 0; i < filas; i++)
{
for (int j = 0; j < columnas; j++)
{
Console.Write($"{matriz[i, j]:D2} ");
}
Console.WriteLine();
}
}
}
Arrays tridimensionales y de mayor dimensión
C# permite crear arrays de cualquier número de dimensiones, aunque en la práctica raramente se usan más de tres dimensiones:
using System;
class Program
{
static void Main()
{
// Array tridimensional: representa un cubo de datos
// Por ejemplo: datos de temperatura por [edificio, piso, habitación]
double[,,] temperaturas = new double[3, 4, 5]; // 3 edificios, 4 pisos, 5 habitaciones
// Inicializar con valores aleatorios (simulando temperaturas)
Random random = new Random();
for (int edificio = 0; edificio < 3; edificio++)
{
for (int piso = 0; piso < 4; piso++)
{
for (int habitacion = 0; habitacion < 5; habitacion++)
{
temperaturas[edificio, piso, habitacion] = 18.0 + random.NextDouble() * 8; // Entre 18°C y 26°C
}
}
}
// Mostrar información del array
Console.WriteLine($"Dimensiones del array: {temperaturas.Rank}");
Console.WriteLine($"Edificios: {temperaturas.GetLength(0)}");
Console.WriteLine($"Pisos por edificio: {temperaturas.GetLength(1)}");
Console.WriteLine($"Habitaciones por piso: {temperaturas.GetLength(2)}");
Console.WriteLine($"Total de mediciones: {temperaturas.Length}");
// Mostrar temperaturas del primer edificio, primer piso
Console.WriteLine("\nTemperaturas del Edificio 1, Piso 1:");
for (int habitacion = 0; habitacion < temperaturas.GetLength(2); habitacion++)
{
double temp = temperaturas[0, 0, habitacion];
Console.WriteLine($" Habitación {habitacion + 1}: {temp:F1}°C");
}
// Calcular temperatura promedio por edificio
for (int edificio = 0; edificio < temperaturas.GetLength(0); edificio++)
{
double suma = 0;
int contador = 0;
for (int piso = 0; piso < temperaturas.GetLength(1); piso++)
{
for (int habitacion = 0; habitacion < temperaturas.GetLength(2); habitacion++)
{
suma += temperaturas[edificio, piso, habitacion];
contador++;
}
}
double promedio = suma / contador;
Console.WriteLine($"\nTemperatura promedio Edificio {edificio + 1}: {promedio:F1}°C");
}
}
}
Aplicaciones prácticas
Juego de tres en raya (Tic-Tac-Toe)
using System;
class TresEnRaya
{
private char[,] tablero;
private char jugadorActual;
public TresEnRaya()
{
tablero = new char[3, 3];
jugadorActual = 'X';
InicializarTablero();
}
private void InicializarTablero()
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
tablero[i, j] = ' ';
}
}
}
public void MostrarTablero()
{
Console.WriteLine("\n 0 1 2");
for (int i = 0; i < 3; i++)
{
Console.Write($"{i} ");
for (int j = 0; j < 3; j++)
{
Console.Write($"{tablero[i, j]}");
if (j < 2) Console.Write(" | ");
}
Console.WriteLine();
if (i < 2) Console.WriteLine(" ---------");
}
Console.WriteLine();
}
public bool HacerMovimiento(int fila, int columna)
{
if (fila >= 0 && fila < 3 && columna >= 0 && columna < 3 && tablero[fila, columna] == ' ')
{
tablero[fila, columna] = jugadorActual;
return true;
}
return false;
}
public bool VerificarVictoria()
{
// Verificar filas y columnas
for (int i = 0; i < 3; i++)
{
if ((tablero[i, 0] == jugadorActual && tablero[i, 1] == jugadorActual && tablero[i, 2] == jugadorActual) ||
(tablero[0, i] == jugadorActual && tablero[1, i] == jugadorActual && tablero[2, i] == jugadorActual))
{
return true;
}
}
// Verificar diagonales
if ((tablero[0, 0] == jugadorActual && tablero[1, 1] == jugadorActual && tablero[2, 2] == jugadorActual) ||
(tablero[0, 2] == jugadorActual && tablero[1, 1] == jugadorActual && tablero[2, 0] == jugadorActual))
{
return true;
}
return false;
}
public bool TableroCompleto()
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (tablero[i, j] == ' ') return false;
}
}
return true;
}
public void CambiarJugador()
{
jugadorActual = jugadorActual == 'X' ? 'O' : 'X';
}
public char ObtenerJugadorActual()
{
return jugadorActual;
}
static void Main()
{
TresEnRaya juego = new TresEnRaya();
bool juegoTerminado = false;
Console.WriteLine("¡Bienvenido al Tres en Raya!");
Console.WriteLine("Introduce fila y columna (0-2) para hacer tu movimiento");
while (!juegoTerminado)
{
juego.MostrarTablero();
Console.WriteLine($"Turno del jugador {juego.ObtenerJugadorActual()}");
try
{
Console.Write("Fila: ");
int fila = int.Parse(Console.ReadLine());
Console.Write("Columna: ");
int columna = int.Parse(Console.ReadLine());
if (juego.HacerMovimiento(fila, columna))
{
if (juego.VerificarVictoria())
{
juego.MostrarTablero();
Console.WriteLine($"¡El jugador {juego.ObtenerJugadorActual()} ha ganado!");
juegoTerminado = true;
}
else if (juego.TableroCompleto())
{
juego.MostrarTablero();
Console.WriteLine("¡Empate!");
juegoTerminado = true;
}
else
{
juego.CambiarJugador();
}
}
else
{
Console.WriteLine("Movimiento inválido. Intenta de nuevo.");
}
}
catch (Exception)
{
Console.WriteLine("Entrada inválida. Introduce números entre 0 y 2.");
}
}
}
}
Consideraciones de rendimiento y memoria
Ventajas de los arrays multidimensionales
Ventaja | Descripción |
---|---|
Localidad espacial | Los elementos se almacenan contiguamente en memoria |
Acceso directo | Acceso O(1) a cualquier elemento usando índices |
Eficiencia de memoria | Menor overhead comparado con arrays de arrays |
Simplicidad sintáctica | Sintaxis más limpia para operaciones matriciales |
Limitaciones importantes
- Tamaño fijo: Las dimensiones no pueden cambiar después de la creación
- Estructura rectangular: No se pueden tener filas de diferente longitud
- Inicialización completa: Se debe especificar el tamaño de todas las dimensiones
Resumen
Los arrays multidimensionales en C# proporcionan una estructura eficiente y elegante para manejar datos organizados en múltiples dimensiones. Su característica principal es mantener una estructura rectangular donde todas las filas tienen exactamente el mismo número de columnas, lo que los hace ideales para representar matrices matemáticas, tablas de datos y estructuras similares.
Hemos explorado desde la declaración e inicialización básica hasta aplicaciones prácticas como operaciones matemáticas con matrices y juegos. Los arrays multidimensionales ofrecen ventajas significativas en términos de rendimiento y simplicidad sintáctica, especialmente cuando trabajamos con datos que se organizan naturalmente en forma tabular. En el próximo artículo, exploraremos las listas y colecciones dinámicas, que nos proporcionarán mayor flexibilidad para manejar conjuntos de datos que pueden cambiar de tamaño durante la ejecución del programa.