Ir al contenido principal

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.