CLASE_5 Arreglos Unidimensionales y Multidimensionales en C++

 


A continuación, te presento un tutorial sobre bucles anidados y vectores unidimensionales en C++


Bucles Anidados y Vectores Unidimensionales en C++: Buscando Duplicados

¡Hola! En este tutorial, vamos a explorar dos conceptos fundamentales en la programación que trabajan muy bien juntos: los bucles anidados y los vectores unidimensionales. Para ello, analizaremos un código C++ que busca números duplicados dentro de un conjunto de datos. Este ejemplo práctico te ayudará a entender cómo estas herramientas se combinan para resolver problemas comunes.


1. Entendiendo el Vector Unidimensional

Antes de sumergirnos en los bucles, recordemos qué es un vector unidimensional.

Imagina un vector como una fila de casilleros, cada uno con un número de identificación único (su índice), empezando desde 0. Dentro de cada casillero, puedes guardar un valor.

En nuestro código:

C++
vector<int> cedula = {2, 1, 7, 2, 1, 1, 9, 5};
  • vector<int>: Indica que estamos creando un vector que guardará números enteros (int). La librería <vector> nos permite usar este tipo de dato dinámico, que es más flexible que los arreglos tradicionales.
  • cedula: Es el nombre de nuestro vector.
  • = {2, 1, 7, 2, 1, 1, 9, 5};: Son los valores iniciales que se guardan en los casilleros del vector.

Así se vería nuestro vector cedula en memoria:

| Índice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | :----- | :- | :- | :- | :- | :- | :- | :- | :- | | Valor | 2 | 1 | 7 | 2 | 1 | 1 | 9 | 5 |

Podemos acceder a cualquier valor usando su índice, por ejemplo, cedula[0] es 2, cedula[1] es 1, y así sucesivamente.


2. Bucles Anidados: Bucles Dentro de Otros Bucles

Un bucle anidado es simplemente un bucle dentro de otro bucle. Piensa en un reloj: la manecilla de los minutos (bucle interno) da 60 vueltas completas por cada vuelta que da la manecilla de las horas (bucle externo).

En programación, los bucles anidados son muy útiles para recorrer estructuras de datos bidimensionales (como matrices) o, como en nuestro caso, para comparar cada elemento de un vector con todos los demás elementos del mismo vector.

En nuestro código, tenemos dos bucles for:

C++
for (size_t i = 0; i < cedula.size(); ++i) {     // Bucle EXTERNO
    for (size_t j = 0; j < cedula.size(); ++j) { // Bucle INTERNO
        // ... código de comparación ...
    }
}
  • Bucle Externo (for (size_t i = 0; i < cedula.size(); ++i)):

    • La variable i (índice externo) comenzará en 0 y aumentará de uno en uno hasta que i sea menor que el tamaño del vector (cedula.size() que es 8).
    • En cada iteración de este bucle, i seleccionará un elemento "base" del vector.
  • Bucle Interno (for (size_t j = 0; j < cedula.size(); ++j)):

    • La variable j (índice interno) también comenzará en 0 y aumentará de uno en uno hasta que j sea menor que el tamaño del vector.
    • ¡Importante! Por cada valor de i en el bucle externo, el bucle interno (j) se ejecutará completamente desde 0 hasta el final. Esto significa que cada elemento seleccionado por i será comparado con todos los elementos seleccionados por j.

3. El Algoritmo de Búsqueda de Duplicados (Fuerza Bruta)

El propósito de nuestro código es encontrar si existe al menos un número duplicado en el vector cedula. Este enfoque es un ejemplo clásico de un algoritmo de fuerza bruta para encontrar duplicados, ya que compara cada elemento con cada uno de los demás.

Vamos a analizar la lógica dentro de los bucles:

C++
if (i != j && cedula[i] == cedula[j]) {
    cout << "Se encontro un duplicado: " << cedula[i] << " (en los indices " << i << " y " << j << ")" << endl;
    encontrado = true;
    break; // Rompe el bucle interno
}
  • if (i != j && cedula[i] == cedula[j]): Esta es la condición clave para detectar un duplicado.
    • i != j: Asegura que no estemos comparando un elemento consigo mismo. Un elemento siempre es igual a sí mismo, pero eso no cuenta como un "duplicado" en el sentido de que haya otra instancia del mismo valor.
    • cedula[i] == cedula[j]: Verifica si el valor en la posición i es igual al valor en la posición j.
  • Si la condición es verdadera (se encuentra un duplicado diferente de sí mismo):
    • Se imprime un mensaje indicando el número duplicado y sus índices.
    • encontrado = true;: Se establece una bandera booleana (bool) en true para recordar que ya encontramos un duplicado.
    • break;: Esta sentencia es crucial. ¡Rompe el bucle interno (j)! Una vez que encontramos el primer duplicado, no necesitamos seguir comparando el cedula[i] actual con el resto de los elementos.

Después del bucle interno, hay otra condición para romper el bucle externo:

C++
if (encontrado) {
    break; // Rompe el bucle externo
}
  • Si encontrado es true (porque se encontró un duplicado en alguna de las iteraciones internas), entonces esta línea ejecuta break; para romper el bucle externo (i). ¿Por qué? Porque el objetivo del programa es solo saber si existe al menos un duplicado. Una vez que lo encontramos, podemos detener la búsqueda por completo.

Finalmente, si al terminar todos los bucles (o al romperlos) la variable encontrado sigue siendo false, significa que no se encontró ningún duplicado:

C++
if (!encontrado) { // '!' significa "NO", así que '!encontrado' es "si encontrado es falso"
    cout << "No se encontraron numeros duplicados en el array." << endl;
}

4. ¿Cómo se Ejecuta el Código? (Traza Simplificada)

Consideremos cedula = {2, 1, 7, 2, 1, 1, 9, 5}.

  • i = 0 (valor cedula[0] = 2)

    • j = 0: i == j, se salta.
    • j = 1: cedula[0] (2) != cedula[1] (1).
    • j = 2: cedula[0] (2) != cedula[2] (7).
    • j = 3: i != j es true, cedula[0] (2) == cedula[3] (2). ¡Duplicado encontrado!
      • Se imprime: Se encontro un duplicado: 2 (en los indices 0 y 3)
      • encontrado = true.
      • break; (sale del bucle j).
    • El bucle externo verifica if (encontrado). Como es true, break; (sale del bucle i).
  • El programa termina la ejecución de los bucles y pasa a la condición final.

  • if (!encontrado): !true es false, así que no se imprime el mensaje "No se encontraron duplicados".

Salida del programa:

Se encontro un duplicado: 2 (en los indices 0 y 3)

5. Compilación y Ejecución

Para probar este código:

  1. Guarda el código: Copia el código completo y guárdalo en un archivo llamado, por ejemplo, buscar_duplicados.cpp.
  2. Abre una terminal/línea de comandos: Navega hasta el directorio donde guardaste el archivo.
  3. Compila: Usa un compilador de C++ (como g++):
    Bash
    g++ buscar_duplicados.cpp -o buscar_duplicados
    
    Esto creará un archivo ejecutable llamado buscar_duplicados (o buscar_duplicados.exe en Windows).
  4. Ejecuta:
    Bash
    ./buscar_duplicados
    

Este tutorial te ha proporcionado una visión clara de cómo los bucles anidados se utilizan para realizar comparaciones exhaustivas en un vector unidimensional, permitiendo la detección de duplicados. Es un patrón común que encontrarás en muchos problemas de programación.

código completo:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> cedula = {2, 1, 7, 2, 1, 1, 9, 5};
    bool encontrado = false;

    for (size_t i = 0; i < cedula.size(); ++i) {
        for (size_t j = 0; j < cedula.size(); ++j) {
            if (i != j && cedula[i] == cedula[j]) {
                cout << "Se encontro un duplicado: " << cedula[i]
 << " (en los indices " << i << " y " << j << ")" << endl;
                encontrado = true;
                break;
            }
        }
        if (encontrado) {
            break;
        }
    }

    if (!encontrado) {
        cout << "No se encontraron numeros duplicados en el array." << endl;
    }

    return 0;
}


¡Excelente! Con el código que proporcionaste, vamos a crear un tutorial que te ayudará a comprender los bucles anidados y los arreglos bidimensionales de una manera muy práctica: generando tablas de multiplicar.


Bucles Anidados y Arreglos Bidimensionales en C++: Generando Tablas de Multiplicar

¡Hola! Hoy exploraremos cómo los bucles anidados y los arreglos bidimensionales se combinan para manejar y organizar datos de forma estructurada. Utilizaremos un ejemplo muy claro: la creación y visualización de tablas de multiplicar completas.


1. Entendiendo el Arreglo Bidimensional (Matriz)

Mientras que un vector unidimensional es como una fila de casilleros, un arreglo bidimensional (o matriz) es como una cuadrícula o una hoja de cálculo, con filas y columnas. Cada "celda" de la cuadrícula tiene dos índices para identificarla: uno para la fila y otro para la columna.

En nuestro código:

C++
const int NUM_TABLAS = 9;   // Definimos el número de tablas (filas)
const int MULTIPLICADORES = 10; // Definimos el número de multiplicadores (columnas)

int tablasDeMultiplicar[NUM_TABLAS][MULTIPLICADORES];
  • int tablasDeMultiplicar[NUM_TABLAS][MULTIPLICADORES];: Declara un arreglo bidimensional llamado tablasDeMultiplicar.
    • NUM_TABLAS (9): Representa el número de filas. En nuestro caso, serán las tablas del 1 al 9.
    • MULTIPLICADORES (10): Representa el número de columnas. Serán los resultados de multiplicar hasta 10 (ej. ×1, ×2, ... ×10).

Piensa en esta matriz así:

Columna 0 (x1)Columna 1 (x2)...Columna 9 (x10)
Fila 0 (Tabla del 1)...
Fila 1 (Tabla del 2)...
...............
Fila 8 (Tabla del 9)...

Para acceder a un elemento, usarías tablasDeMultiplicar[fila][columna]. Por ejemplo, tablasDeMultiplicar[0][4] almacenaría el resultado de (porque la fila 0 es la tabla del 1 y la columna 4 es el multiplicador 5).


2. Bucles Anidados: Llenando la Matriz

Para llenar cada "celda" de nuestra matriz tablasDeMultiplicar, necesitamos recorrer tanto las filas como las columnas. Aquí es donde los bucles anidados son indispensables.

C++
for (int i = 0; i < NUM_TABLAS; ++i) { // Bucle EXTERNO: Recorre las FILAS (tablas)
    for (int j = 0; j < MULTIPLICADORES; ++j) { // Bucle INTERNO: Recorre las COLUMNAS (multiplicadores)
        // La fila (i) representa la tabla actual (ej. 0 para tabla del 1, 1 para tabla del 2, etc.)
        // La columna (j) representa el multiplicador actual (ej. 0 para x1, 1 para x2, etc.)
        tablasDeMultiplicar[i][j] = (i + 1) * (j + 1);
    }
}
  • Bucle Externo (for (int i = 0; i < NUM_TABLAS; ++i)):

    • Controla las filas de nuestra matriz. La variable i irá de 0 a 8 (para 9 tablas).
    • i + 1 se usa para obtener el número de tabla real (ej. 0 + 1 = 1 para la tabla del 1, 1 + 1 = 2 para la tabla del 2, etc.).
  • Bucle Interno (for (int j = 0; j < MULTIPLICADORES; ++j)):

    • Controla las columnas dentro de cada fila. La variable j irá de 0 a 9 (para 10 multiplicadores).
    • Por cada iteración del bucle externo (i), el bucle interno (j) se ejecutará completamente de 0 a 9.
    • j + 1 se usa para obtener el multiplicador real (ej. 0 + 1 = 1 para ×1, 1 + 1 = 2 para ×2, etc.).
  • tablasDeMultiplicar[i][j] = (i + 1) * (j + 1);:

    • Esta línea crucial calcula el resultado de la multiplicación para la celda actual y lo almacena.
    • Por ejemplo, cuando i=0 (Tabla del 1) y j=4 (Multiplicador 5), se almacenará (0+1) * (4+1) = 1 * 5 = 5 en tablasDeMultiplicar[0][4].

3. Bucles Anidados: Mostrando la Matriz

Una vez que la matriz está llena, necesitamos otra serie de bucles anidados para imprimir su contenido de una manera legible.

C++
for (int tabla = 0; tabla < NUM_TABLAS; ++tabla) { // Bucle EXTERNO: Recorre las "filas" (tablas)
    cout << "Tabla del " << (tabla + 1) << endl; // Imprime el encabezado de la tabla (ej: Tabla del 1)
    for (int x = 0; x < MULTIPLICADORES; ++x) {    // Bucle INTERNO: Recorre las "columnas" (operaciones)
        // Accedemos al resultado almacenado y lo imprimimos.
        cout << "[ " << (tabla + 1) << " * " << (x + 1) << " = " << tablasDeMultiplicar[tabla][x] << " ] ";
    }
    cout << "\n----------------------------------------\n"; // Separador entre tablas para mejor legibilidad
}
  • Esta sección es muy similar a la de llenado, pero en lugar de asignar valores, los estamos leyendo y mostrando en pantalla.
  • Las variables tabla y x se utilizan aquí en lugar de i y j para mayor claridad, pero su función es la misma: tabla itera sobre las filas y x sobre las columnas.
  • cout << "[ " << (tabla + 1) << " * " << (x + 1) << " = " << tablasDeMultiplicar[tabla][x] << " ] "; : Imprime cada operación y su resultado de manera formateada, accediendo al valor en tablasDeMultiplicar[tabla][x].

4. Código Completo y Ejecución

Aquí está el código completo para que puedas copiarlo, compilarlo y ejecutarlo:

C++
#include <iostream> // Para usar cout y endl

using namespace std; // Para no tener que usar std:: antes de cout, etc.

int main() {
    // Definimos el tamaño de nuestra matriz usando constantes para mayor claridad
    const int NUM_TABLAS = 9;   // Representa las filas (tablas del 1 al 9)
    const int MULTIPLICADORES = 10; // Representa las columnas (multiplicadores del 1 al 10)

    // Declaramos nuestro arreglo bidimensional (matriz)
    int tablasDeMultiplicar[NUM_TABLAS][MULTIPLICADORES];

    // Bucle para LLENAR la matriz con los resultados de las tablas de multiplicar
    for (int i = 0; i < NUM_TABLAS; ++i) { // Recorre las filas (tablas)
        for (int j = 0; j < MULTIPLICADORES; ++j) { // Recorre las columnas (multiplicadores)
            // Calculamos el valor y lo asignamos a la celda correspondiente
            // (i + 1) para obtener el número de tabla real (del 1 al 9)
            // (j + 1) para obtener el multiplicador real (del 1 al 10)
            tablasDeMultiplicar[i][j] = (i + 1) * (j + 1);
        }
    }

    // Bucle para MOSTRAR el contenido de la matriz (las tablas de multiplicar)
    for (int tabla = 0; tabla < NUM_TABLAS; ++tabla) { // Recorre las filas para imprimir cada tabla
        // Imprime el encabezado para saber de qué tabla se trata
        cout << "Tabla del " << (tabla + 1) << endl; 
        
        for (int x = 0; x < MULTIPLICADORES; ++x) { // Recorre las columnas para imprimir cada operación
            // Accedemos al resultado almacenado en la matriz y lo mostramos formateado
            cout << "[ " << (tabla + 1) << " * " << (x + 1) << " = " << tablasDeMultiplicar[tabla][x] << " ] ";
        }
        cout << "\n----------------------------------------\n"; // Un separador para diferenciar las tablas
    }

    return 0; // Indica que el programa finalizó correctamente
}

Pasos para Compilar y Ejecutar:

  1. Guarda: Copia el código en un archivo de texto y guárdalo como tablas_multiplicar.cpp.
  2. Compila: Abre tu terminal o línea de comandos y navega hasta donde guardaste el archivo. Usa un compilador de C++ (como g++):
    Bash
    g++ tablas_multiplicar.cpp -o tablas_multiplicar
    
  3. Ejecuta:
    Bash
    ./tablas_multiplicar
    

Verás las tablas de multiplicar impresas en tu consola.


Este tutorial te ha mostrado cómo los bucles anidados son la herramienta perfecta para trabajar con arreglos bidimensionales, permitiéndote procesar y organizar datos de forma tabular. Esta combinación es fundamental para tareas como la manipulación de imágenes, juegos (tableros), o cualquier dato que pueda representarse en filas y columnas.

Código completo

#include <iostream> 
using namespace std; 
int main() {

    const int NUM_TABLAS = 9; 
    const int MULTIPLICADORES = 10; 

    int tablasDeMultiplicar[NUM_TABLAS][MULTIPLICADORES];

    for (int i = 0; i < NUM_TABLAS; ++i) {
        for (int j = 0; j < MULTIPLICADORES; ++j) {  
            tablasDeMultiplicar[i][j] = (i + 1) * (j + 1);
        }
    }
    for (int tabla = 0; tabla < NUM_TABLAS; ++tabla) { // Recorre las "filas" para imprimir cada tabla
        cout << "Tabla del " << (tabla + 1) << endl; // Imprime el encabezado de la tabla (ej: Tabla del 1)
        for (int x = 0; x < MULTIPLICADORES; ++x) {   // Recorre las "columnas" para imprimir cada operación
            // Accedemos al resultado almacenado y lo imprimimos.
            cout << "[ " << (tabla + 1) << " * " << (x + 1) << " = " << tablasDeMultiplicar[tabla][x] << " ] ";
        }
        cout << "\n----------------------------------------\n"; // Separador de tablas
    }

    return 0; // Indica que el programa finalizó correctamente
}



Arreglos Multidimensionales (Tres Dimensiones) en C++: Un Almacén Virtual

¡Hola! Hasta ahora hemos trabajado con arreglos unidimensionales (listas) y bidimensionales (tablas o matrices). Hoy daremos un paso más allá para explorar los arreglos multidimensionales de tres dimensiones. Piensa en ellos como cubos o pilas de tablas. Usaremos un ejemplo práctico: la simulación de un almacén con niveles, pasillos y estantes para entender cómo se organizan los datos en un espacio tridimensional.


1. ¿Qué es un Arreglo Tridimensional?

Un arreglo bidimensional tiene filas y columnas (x, y). Un arreglo tridimensional añade una tercera dimensión, que podemos llamar "profundidad" o "altura" (x, y, z). Es como tener múltiples matrices apiladas una encima de la otra.

En C++, puedes declarar un arreglo tridimensional especificando tres tamaños:

tipo nombre[tamaño1][tamaño2][tamaño3];

En nuestro código, utilizamos std::vector de forma anidada para crear un arreglo tridimensional, que es una práctica más moderna y flexible que los arreglos C-style fijos.

C++
const int NIVELES = 3;
const int PASILLOS = 5;
const int ESTANTES_POR_PASILLO = 10;

// Declaración e inicialización de un arreglo tridimensional usando vectores anidados
std::vector<std::vector<std::vector<std::string>>> almacen(
    NIVELES,
    std::vector<std::vector<std::string>>(
        PASILLOS,
        std::vector<std::string>(ESTANTES_POR_PASILLO, ESTANTE_VACIO) // Inicializa con "VACIO"
    )
);

Aquí, almacen representa nuestro espacio tridimensional:

  • NIVELES (3): La primera dimensión. Piensa en la altura del almacén, como si fueran 3 pisos.
  • PASILLOS (5): La segunda dimensión. Dentro de cada nivel, hay 5 pasillos.
  • ESTANTES_POR_PASILLO (10): La tercera dimensión. Dentro de cada pasillo, hay 10 estantes.

Cada celda de este arreglo (almacen[nivel][pasillo][estante]) puede almacenar una std::string, que representa el nombre de un producto (o "VACIO" si está desocupado).

Para acceder a un elemento específico en este "almacén", necesitas tres índices: almacen[nivel][pasillo][estante].


2. Inicialización y Asignación de Productos

El código inicializa todos los estantes como "VACIO" para simular un almacén desocupado. Luego, asigna algunos productos en ubicaciones específicas:

C++
const std::string ESTANTE_VACIO = "VACIO"; // Una constante para el estado vacío

// ... (declaración del almacén) ...

std::cout << "\nAsignando productos a estantes..." << std::endl;
almacen[0][0][0] = "Producto_A_123"; // Nivel 0, Pasillo 0, Estante 0
almacen[0][0][1] = "Producto_B_456"; // Nivel 0, Pasillo 0, Estante 1
almacen[1][2][5] = "Producto_C_789"; // Nivel 1, Pasillo 2, Estante 5
almacen[2][4][9] = "Producto_D_012"; // Nivel 2, Pasillo 4, Estante 9 (el ultimo estante)
almacen[0][3][2] = "Producto_E_345"; // Nivel 0, Pasillo 3, Estante 2

Aquí vemos cómo se usa la notación de tres corchetes [ ] [ ] [ ] para especificar la ubicación exacta de un producto dentro del almacén. Los índices, como siempre en C++, comienzan desde 0.


3. Acceso y Verificación de Estantes Específicos

Para demostrar cómo acceder a un estante en particular, el código utiliza una función lambda (una función anónima) mostrarEstadoEstante para verificar el contenido de una ubicación dada:

C++
auto mostrarEstadoEstante = [&](int nivel, int pasillo, int estante) {
    if (nivel >= 0 && nivel < NIVELES && // Validar nivel
        pasillo >= 0 && pasillo < PASILLOS && // Validar pasillo
        estante >= 0 && estante < ESTANTES_POR_PASILLO) { // Validar estante
        std::cout << "Nivel " << nivel << ", Pasillo " << pasillo
                  << ", Estante " << estante << ": " << almacen[nivel][pasillo][estante] << std::endl;
    } else {
        std::cout << "Coordenadas de estante fuera de rango." << std::endl;
    }
};

// Verificando el estado de algunos estantes
std::cout << "\n--- Verificacion de Estantes Especificos ---" << std::endl;
mostrarEstadoEstante(0, 0, 0); // Un estante con producto
mostrarEstadoEstante(0, 0, 2); // Un estante vacío
mostrarEstadoEstante(99, 0, 0); // Un ejemplo fuera de rango

Esta función es útil para verificar que el acceso a los arreglos esté dentro de los límites definidos (para evitar errores de "fuera de rango").


4. Recorrido Completo del Almacén con Bucles Anidados (¡Triple Bucle!)

Para recorrer y mostrar el contenido de todo el almacén tridimensional, necesitamos tres bucles anidados. Cada bucle se encarga de una de las dimensiones:

C++
std::cout << "\n--- Inventario Completo del Almacen ---" << std::endl;
int productosAlmacenados = 0;
for (int n = 0; n < NIVELES; ++n) { // Bucle EXTERNO: Recorre los NIVELES
    std::cout << "\nNIVEL " << n << ":" << std::endl;
    for (int p = 0; p < PASILLOS; ++p) { // Bucle MEDIO: Recorre los PASILLOS dentro de cada nivel
        std::cout << "  Pasillo " << p << ": ";
        for (int e = 0; e < ESTANTES_POR_PASILLO; ++e) { // Bucle INTERNO: Recorre los ESTANTES por pasillo
            // Accedemos al contenido del estante actual
            if (almacen[n][p][e] != ESTANTE_VACIO) {
                std::cout << "[" << almacen[n][p][e] << "] ";
                productosAlmacenados++;
            } else {
                std::cout << "[    " << ESTANTE_VACIO << "    ] "; // Formato para estantes vacíos
            }
        }
        std::cout << std::endl; // Salto de línea para el siguiente pasillo
    }
}
std::cout << "\nTotal de productos almacenados: " << productosAlmacenados << std::endl;
  • El bucle más externo (for (int n = 0; n < NIVELES; ++n)) itera sobre los NIVELES.
  • Por cada nivel, el bucle intermedio (for (int p = 0; p < PASILLOS; ++p)) itera sobre los PASILLOS.
  • Finalmente, por cada pasillo, el bucle más interno (for (int e = 0; e < ESTANTES_POR_PASILLO; ++e)) itera sobre los ESTANTES.

Esta combinación de tres bucles asegura que se visite cada ubicación única en el espacio tridimensional del almacén. La condición if (almacen[n][p][e] != ESTANTE_VACIO) se usa para imprimir de manera diferente los estantes que contienen un producto versus los que están vacíos, y para contar los productos.


5. Modificando Contenido

Así como podemos asignar valores, también podemos modificarlos o "eliminar" productos asignando el valor ESTANTE_VACIO a una ubicación:

C++
// 5. Eliminar un producto de un estante
std::cout << "\n--- Retirando un Producto ---" << std::endl;
int nivelARetirar = 1;
int pasilloARetirar = 2;
int estanteARetirar = 5;
if (almacen[nivelARetirar][pasilloARetirar][estanteARetirar] != ESTANTE_VACIO) {
    std::cout << "Retirando " << almacen[nivelARetirar][pasilloARetirar][estanteARetirar]
              << " de Nivel " << nivelARetirar << ", Pasillo " << pasilloARetirar
              << ", Estante " << estanteARetirar << std::endl;
    almacen[nivelARetirar][pasilloARetirar][estanteARetirar] = ESTANTE_VACIO; // Lo marca como vacío
    mostrarEstadoEstante(nivelARetirar, pasilloARetirar, estanteARetirar); // Muestra el estado actualizado
} else {
    std::cout << "El estante ya esta vacio o no existe el producto." << std::endl;
}

Esto demuestra cómo puedes interactuar con una celda específica del arreglo tridimensional para actualizar su contenido.


6. Código Completo y Ejecución

Aquí tienes el código completo para que puedas compilarlo y ejecutarlo:

C++
#include <iostream> // Para entrada y salida estándar (cout, endl)
#include <string>   // Para usar std::string
#include <vector>   // Para usar std::vector (más flexible que arrays fijos)

// Usamos el namespace std para no tener que escribir std::cout, std::endl, etc.
using namespace std;

// Definimos una constante para representar un estante vacío
const std::string ESTANTE_VACIO = "VACIO";

int main() {
    // Dimensiones del almacén:
    // NIVELES: Altura del almacén
    // PASILLOS: Número de pasillos en cada nivel
    // ESTANTES_POR_PASILLO: Número de estantes en cada pasillo
    const int NIVELES = 3;
    const int PASILLOS = 5;
    const int ESTANTES_POR_PASILLO = 10;

    // 1. Declaración e inicialización del array tridimensional
    // Usamos std::vector<std::vector<std::vector<std::string>>> para mayor flexibilidad.
    // Esto es equivalente a un array string almacenes[NIVELES][PASILLOS][ESTANTES_POR_PASILLO];
    std::vector<std::vector<std::vector<std::string>>> almacen(
        NIVELES, // El primer vector tiene 'NIVELES' elementos
        std::vector<std::vector<std::string>>(
            PASILLOS, // Cada elemento del primer vector es un vector con 'PASILLOS' elementos
            std::vector<std::string>(ESTANTES_POR_PASILLO, ESTANTE_VACIO) // Cada elemento del segundo vector es un vector con 'ESTANTES_POR_PASILLO' elementos, inicializados a "VACIO"
        )
    );

    std::cout << "--- Simulacion de Asignacion de Recursos en Almacen ---" << std::endl;

    // 2. Asignación de algunos productos a estantes específicos
    std::cout << "\nAsignando productos a estantes..." << std::endl;
    almacen[0][0][0] = "Producto_A_123"; // Nivel 0, Pasillo 0, Estante 0
    almacen[0][0][1] = "Producto_B_456"; // Nivel 0, Pasillo 0, Estante 1
    almacen[1][2][5] = "Producto_C_789"; // Nivel 1, Pasillo 2, Estante 5
    almacen[2][4][9] = "Producto_D_012"; // Nivel 2, Pasillo 4, Estante 9 (el ultimo estante)
    almacen[0][3][2] = "Producto_E_345"; // Nivel 0, Pasillo 3, Estante 2

    // 3. Función para mostrar el estado actual de un estante
    // 'auto' permite que el compilador infiera el tipo de la lambda.
    // '&' captura las variables del entorno circundante por referencia (como NIVELES, PASILLOS, etc.)
    auto mostrarEstadoEstante = [&](int nivel, int pasillo, int estante) {
        // Validación de límites para evitar errores de acceso
        if (nivel >= 0 && nivel < NIVELES &&
            pasillo >= 0 && pasillo < PASILLOS &&
            estante >= 0 && estante < ESTANTES_POR_PASILLO) {
            std::cout << "Nivel " << nivel << ", Pasillo " << pasillo
                      << ", Estante " << estante << ": " << almacen[nivel][pasillo][estante] << std::endl;
        } else {
            std::cout << "Coordenadas de estante fuera de rango." << std::endl;
        }
    };

    // Verificando el estado de algunos estantes
    std::cout << "\n--- Verificacion de Estantes Especificos ---" << std::endl;
    mostrarEstadoEstante(0, 0, 0); // Existe y tiene un producto
    mostrarEstadoEstante(1, 2, 5); // Existe y tiene un producto
    mostrarEstadoEstante(0, 0, 2); // Existe y está vacío
    mostrarEstadoEstante(2, 4, 9); // El último estante con producto
    mostrarEstadoEstante(99, 0, 0); // Ejemplo de coordenadas fuera de rango

    // 4. Recorrido completo del almacén para ver el inventario
    std::cout << "\n--- Inventario Completo del Almacen ---" << std::endl;
    int productosAlmacenados = 0;
    // Bucle externo para los niveles
    for (int n = 0; n < NIVELES; ++n) {
        std::cout << "\nNIVEL " << n << ":" << std::endl;
        // Bucle medio para los pasillos
        for (int p = 0; p < PASILLOS; ++p) {
            std::cout << "  Pasillo " << p << ": ";
            // Bucle interno para los estantes
            for (int e = 0; e < ESTANTES_POR_PASILLO; ++e) {
                // Verificamos si el estante está vacío o tiene un producto
                if (almacen[n][p][e] != ESTANTE_VACIO) {
                    std::cout << "[" << almacen[n][p][e] << "] "; // Mostrar el producto
                    productosAlmacenados++; // Contar el producto
                } else {
                    std::cout << "[    " << ESTANTE_VACIO << "    ] "; // Mostrar que está vacío
                }
            }
            std::cout << std::endl; // Salto de línea para el siguiente pasillo
        }
    }
    std::cout << "\nTotal de productos almacenados: " << productosAlmacenados << std::endl;

    // 5. Eliminar un producto de un estante
    std::cout << "\n--- Retirando un Producto ---" << std::endl;
    int nivelARetirar = 1;
    int pasilloARetirar = 2;
    int estanteARetirar = 5;
    // Antes de retirar, se puede validar si la ubicación contiene algo
    if (almacen[nivelARetirar][pasilloARetirar][estanteARetirar] != ESTANTE_VACIO) {
        std::cout << "Retirando " << almacen[nivelARetirar][pasilloARetirar][estanteARetirar]
                  << " de Nivel " << nivelARetirar << ", Pasillo " << pasilloARetirar
                  << ", Estante " << estanteARetirar << std::endl;
        almacen[nivelARetirar][pasilloARetirar][estanteARetirar] = ESTANTE_VACIO; // Marcar como vacío
        mostrarEstadoEstante(nivelARetirar, pasilloARetirar, estanteARetirar); // Confirmar cambio
    } else {
        std::cout << "El estante ya esta vacio o no existe el producto." << std::endl;
    }

    return 0; // Indica que el programa finalizó correctamente
}

Pasos para Compilar y Ejecutar:

  1. Guarda: Copia el código en un archivo de texto y guárdalo como almacen_3d.cpp.
  2. Compila: Abre tu terminal o línea de comandos y navega hasta donde guardaste el archivo. Usa un compilador de C++ (como g++):
    Bash
    g++ almacen_3d.cpp -o almacen_3d
    
  3. Ejecuta:
    Bash
    ./almacen_3d
    

La salida mostrará la simulación de las operaciones en el almacén, incluyendo el inventario completo.


Comprender los arreglos tridimensionales te abre las puertas a modelar datos en espacios 3D, útil en gráficos de computadora, simulaciones complejas, y más.



Comentarios