¡Domina los Arreglos de Estructuras! Guía Definitiva para Declaración y Uso Efectivopost-template-default single single-post postid-46 single-format-standard et_pb_button_helper_class et_fixed_nav et_show_nav et_secondary_nav_enabled et_primary_nav_dropdown_animation_fade et_secondary_nav_dropdown_animation_fade et_header_style_left et_pb_footer_columns4 et_cover_background et_pb_gutter et_pb_gutters3 et_right_sidebar et_divi_theme et-db
771 715 4434

Hasta ahora, todos los algoritmos que hemos desarrollado hacen uso de objetos que guardan datos individuales, los cuales representan un número, una cadena de texto o un valor lógico. Sin embargo, la verdadera utilidad de la computación radica en poder trabajar con conjuntos de datos, organizados de acuerdo a ciertas reglas que permitan su manipulación y acceso. Los componentes individuales del conjunto se llaman elementos. Para indicar qué posición ocupa cada elemento en el arreglo se emplean uno o más índices.

Introducción a las Estructuras de Datos y Arreglos

Cuando uno declara una variable en un programa, está definiendo un espacio de memoria en la que se podrá almacenar un solo valor. Por ejemplo, cuando colocamos en un programa la sentencia int a; estamos definiendo la variable entera a, la cual sólo podrá almacenar un valor en un instante dado. Por otro lado, cuando definimos un arreglo (estático o dinámico) estamos definiendo un conjunto de variables, todas identificadas por un mismo nombre, diferenciándose cada una por uno o más índices. Por ejemplo, cuando escribimos la sentencia int a[5]; estamos definiendo las variables enteras a[0], a[1], a[2], a[3] y a[4].

Un array (o arreglo) es una estructura de datos con elementos homogéneos, del mismo tipo, numérico o alfanumérico, reconocidos por un nombre en común. La principal característica de los arreglos es la homegeneidad: todos los elementos que contienen deben ser del mismo tipo. No se puede, por ejemplo, mezclar en una matriz valores numéricos y lógicos. Los arreglos son estructuras de datos estáticas, ya que hay que declarar su tamaño antes de utilizarlos. Hemos visto en los capítulos anteriores la cantidad de aplicaciones que podemos desarrollar con este tipo de dato, sin embargo, a pesar de ello, los arreglos tienen un inconveniente, que todos elementos de un arreglo tienen el mismo tipo de dato.

Esta instrucción define un arreglo con el nombre indicado y N dimensiones. Los N parámetros indican la cantidad de dimensiones y el valor máximo de cada una de ellas. Para acceder a un elemento de un array se utiliza un índice. Dependiendo de cuántos índices se deban utilizar para acceder a cada elemento dentro de los arreglos, estos se clasifican en unidimensionales (vectores) o bidimensionales (matrices).

Tipos de Arreglos

Arreglos Unidimensionales (Vectores)

Un arreglo unidimensional o vector tiene n elementos todos del mismo tipo. Cada uno de los elementos ocupa una posición determinada en el vector. Un vector, también llamado array (arreglo) unidimensional, es una estructura de datos que permite agrupar elementos del mismo tipo y almacenarlos en un solo bloque de memoria juntos, uno después de otro. A este grupo de elementos se les identifica por un mismo nombre y la posición en la que se encuentran. La primera posición del array es la posición 0 (cero). Podríamos agrupar en un array una serie de elementos de tipo enteros, flotantes, caracteres, objetos, etc.

Lea también: gestión de memoria para estructuras dinámicas en C

Se puede acceder o hacer referencia a cada elemento mediante el uso de índices, expresados entre corchetes al lado del nombre del vector. De esta forma, si escribimos x[3] hacemos referencia a la tercera posición del vector, que actualmente guarda al valor 2.71. Por ejemplo, el elemento 3 del vector x es el numéro 2.71. Desde el punto de vista de las matemáticas, a una matriz -o conjunto de números o valores- de una dimensión se le llama vector. Un vector es justamente un arreglo de este tipo que sólo utiliza un índice para referenciar a cada uno de sus elementos.

Al igual que todas las variables que empleamos en nuestros algoritmos, los vectores que serán utilizados deben ser declarados en el pseudocódigo, eligiendo un identificador (nombre) e indicando su tipo y su tamaño, es decir, la cantidad de posiciones que contienen. Esto último se señala entre paréntesis al lado del nombre elegido. Todo vector debe tener definido un tipo de dato. Todo vector necesita de una dimensión o tamaño. Cuando declaramos un vector de tipo numérico con la expresión VARIABLE numérica x(5) asumiremos que, además de reservar espacio en memoria para el vector, se le asigna un 0 (cero) en cada posición. Es decir, el vector x es iniciado con ceros, que más tarde pueden ser reemplazados por otros valores.

Crear un vector en C++ es sencillo, siguiendo la siguiente sintaxis:

Tipo nombre[tamaño];

Por ejemplo, podemos declarar un vector de enteros:

int miVector[5];

Podríamos también inicializar el vector en la declaración:

Lea también: sintaxis para crear arrays en Visual Basic

int miVector[] = {10, 20, 30, 40, 50};

Como hay 5 elementos en cada array, automáticamente se le asignará 5 espacios de memoria a cada vector, pero si trato de crear el vector de la forma int a[], el compilador mostrará un error, porque no indiqué el tamaño del vector ni tampoco inicialicé sus elementos.

Se pueden asignar valores a una, varias o todas las posiciones de un vector en cualquier parte del algoritmo. Asigno valores a los elementos de un vector indicando su posición. El proceso de lectura de un arreglo consiste en leer y asignar un valor a cada uno de sus componentes. Similar a la lectura, se debe escribir el valor de cada uno de los componentes. En este caso no es posible asignar directamente un valor a todo el arreglo; sino que se debe asignar el valor deseado a cada componente. Para llenar, recorrer e imprimir un vector podemos utilizar un bucle for.

Es el proceso de organizar los elementos de un vector en algún orden dado que puede ser ascendente o descendente. Consiste en encontrar un determinado valor dentro del conjunto de datos del arreglo, para recuperar alguna información asociada con el valor buscado.

Arreglos Bidimensionales (Matrices)

Un arreglo bidimensional representa lo que habitualmente conocemos en matemática como matriz y por eso también lo llamamos de esa forma. Podemos imaginar que en una matriz los elementos están organizados en filas y columnas formando una tabla. A diferencia de los vectores, las matrices requieren dos índices para señalar la posición de cada elemento, el primero para indicar la fila y el segundo para indicar la columna. Los mismos se colocan entre corchetes, separados por una coma, al lado del identificador de la matriz. Al tamaño de una matriz, es decir, cuántas filas y columnas tiene, se le dice dimensión.

Como hicimos con los vectores, debemos declarar las matrices que vamos a usar en el pseudocódigo, indicando su identificador, tipo y dimensión: VARIABLE numérica x(3, 4). También vamos a asumir que todas las posiciones de una matriz son iniciadas con el valor 0, "" o FALSO si la misma es numérica, carácter o lógica, respectivamente.

Lea también: aprende a usar arreglos de dos dimensiones en Python

En cuanto tenemos declarado una matriz, es posible asignarle valores a cada una de sus casillas, evidentemente estos valores deben coincidir con el tipo de dato que le asignamos a dicha matriz. Veamos la sintaxis para declarar e inicializar una matriz en C++:

Tipo de dato del arreglo;Nombre del arreglo;Corchetes [] dentro de ellos se definirán las filas y columnas del arreglo;int myMatriz1[2][2] = {{1,2},{3,4}};

Aquí hemos declarado una matriz de tipo int de dos filas y dos columnas y la hemos inicializado con diferentes valores. El valor inicial corresponde a la casilla 0,0 (fila cero, columna cero) y tiene el valor de 1, en la fila cero columna uno tenemos el valor de 2, en la fila uno columna cero el valor de 3 y finalmente en la fila uno columna uno el valor de 4. Es importante notar que tanto la fila como la columna comienzan desde cero y no desde uno, por esto la primer casilla corresponde a la fila y columna cero.

Por otro lado, un arreglo de dos dimensiones ilustra claramente las diferencias lógica y física de un dato, pues es una estructura de datos lógicos, útil en programación y en la solución de problemas. Sin embargo, aunque los elementos de dicho arreglo están organizados en un diagrama de dos dimensiones, el hardware de la mayoría de las computadoras no da este tipo de facilidad. Un método para mostrar un arreglo de dos dimensiones en memoria es la representación fila mayor. Bajo esta representación, la primera fila del arreglo ocupa el primer conjunto de posiciones en memoria reservada para el arreglo; la segunda fila, el segundo y así sucesivamente.

Arreglos Multidimensionales

Un arreglo multidimensional contiene más de dos dimensiones, es decir, requiere más de dos índices para identificar a cada uno de sus elementos. La representación matemática o visual ya no es tan sencilla como la de los vectores o matrices. Por ejemplo, en lenguaje C, se definen igual que los vectores, con la excepción de que en este tipo de arreglos se requiere un índice por cada dimensión. Para añadir una nueva "dimensión" en el array basta añadir un nuevo conjunto de corchetes, [], y su índice correspondiente.

Las Estructuras: Organizando Datos Heterogéneos

Si quisiéramos almacenar por medio de un programa una lista de personas en donde por cada una tenemos un código, un nombre y un sueldo, para poder hacerlo tendríamos que definir un arreglo por cada uno de los datos, esto es un arreglo de enteros para el código, un arreglo de cadenas de caracteres para el nombre y uno de punto flotante para el sueldo. El inconveniente sería que los datos de una persona no se pueden manejar, así, como una unidad.

Los registros o "estructuras", como se denominan en el lenguaje C, permiten definir variables que pertenecen también a la categoría de variables estructuradas. En este sentido, al declarar una estructura estaremos definiendo, como en el caso de los arreglos, un conjunto de datos, todos identificados por el mismo nombre, pero con la diferencia que cada elemento del conjunto puede ser de diferente tipo. La forma en que se diferenciará un elemento de otro del conjunto ya no se hará por medio de índices sino que se le asignará a cada elemento un nombre. Cada elemento de una estructura se denominará campo.

Una "declaración de estructura" asigna un nombre a un tipo y especifica una secuencia de valores de variable (denominados "miembros" o "campos" de la estructura) que pueden tener diferentes tipos. Un identificador opcional, denominado "etiqueta", proporciona el nombre del tipo de estructura y se puede usar en referencias posteriores al tipo de estructura. A diferencia de los arreglos, al declarar una estructura no estamos definiendo una variable directamente, si no un "Tipo de dato". La declaración de un tipo de estructura no reserva espacio para una estructura.

La lista de declaración de la estructura (`struct-declaration-list`) especifica los tipos y nombres de los miembros de la estructura. Cada variable declarada en esta lista se define como miembro del tipo de estructura. Las declaraciones de variables dentro de la lista tienen el mismo formato que otras declaraciones de variable, salvo que no pueden contener especificadores o inicializadores de clase de almacenamiento. No se puede declarar un miembro para que tenga el tipo de la estructura en la que aparece. Sin embargo, un miembro se puede declarar como puntero al tipo de estructura en el que aparece siempre que el tipo de estructura tenga una etiqueta.

En el siguiente ejemplo declaramos una estructura llamada persona que contiene dos miembros:

struct Persona { char nombre[50]; int edad;};

El código anterior declara dos variables del tipo de estructura persona (la variable alumno y la variable profesor).

struct Persona alumno;struct Persona profesor;

También podemos crear tipos de datos basados en estructuras utilizando la palabra reservada typedef. Por ejemplo, la estructura employee tiene tres miembros: name, id y class. El miembro name es una matriz de 20 elementos e id y class son miembros simples con tipo int y long, respectivamente.

Para tener acceso a los miembros de una estructura podemos utilizar el operador punto. Utilice la notación de puntos para crear, asignar y acceder a los datos de los campos de las estructuras. Por ejemplo, si tenemos una variable `alumno` de tipo `struct Persona`, podemos acceder a sus campos así: `alumno.nombre` o `alumno.edad`. La manera en que se almacenan las variables de tipo struct permite manejar las variables como una unidad, y a diferencia de los arreglos, se podrán asignar los valores de todos los campos de una variable a otra en una sola operación.

A pesar de que las estructuras de datos se pueden asignar directamente, esto no se puede hacer así cuando se trata de compararlas. Debido a la forma cómo se representa una estructura en memoria, la manera en que se podrían comparar dos estructuras directamente tendría que ser hecho byte a byte; si se encuentra que un byte no coincide, la igualdad en la comparación fracasaría. Por eso, si un campo es definido como un arreglo, nada nos garantiza que todos los bytes coincidan, incluso los que no se usan.

El concepto de estructuras anidadas se refiere a que un tipo de dato struct se puede emplear como tipo de dato para definir uno o más campos en otra estructura.

Declaración de Arreglos de Estructuras

Cuando tenga datos que quiera organizar por nombre, puede utilizar estructuras para almacenarlos. Las estructuras almacenan datos en contenedores llamados campos, a los que se puede acceder por los nombres que se especifiquen. Si el valor almacenado en un campo es un arreglo, se puede utilizar la indexación de arreglos para acceder a sus elementos.

Cuando se almacenan varias estructuras como un arreglo de estructuras, se puede utilizar la indexación de arreglos y la notación de puntos para acceder a cada una de las estructuras y a sus campos. Los arreglos de estructuras pueden ser no escalares. Puede crear un arreglo de estructuras de cualquier tamaño, siempre que cada estructura del arreglo tenga los mismos campos.

Cada registro de paciente del arreglo es una estructura de clase struct. En ocasiones, un arreglo de estructuras se conoce como arreglo struct. No obstante, los términos arreglo struct y arreglo de estructuras significan lo mismo. Para indexar en un arreglo de estructuras, utilice la indexación de arreglos. Para acceder a un campo, utilice la indexación de arreglos y la notación de puntos.

Consideremos el ejemplo de una estructura Paciente y cómo declaramos un arreglo de este tipo:

// Definición de la estructurastruct Paciente { char nombre[100]; int id; float temperatura;};// Declaración de un arreglo de estructuras 'Paciente'struct Paciente listaPacientes[20]; // Un arreglo para 20 pacientes

En este ejemplo, listaPacientes es un arreglo donde cada elemento es una estructura Paciente. Podemos acceder a un paciente específico utilizando la indexación del arreglo, y luego a sus campos utilizando el operador punto. Por ejemplo, para acceder al nombre del segundo paciente (índice 1): listaPacientes[1].nombre.

El siguiente programa es un ejemplo en donde se captura el nombre y edad de 10 empleados y se pasa el arreglo a una función que regresa el promedio de edad. Esto implica el uso de un arreglo de estructuras, donde cada estructura representa un empleado con sus respectivos campos.

También se puede indexar en un arreglo almacenado mediante un campo. Es importante notar que solo se puede indexar en una parte de un campo cuando se hace referencia a un único elemento de un arreglo de estructuras. Por ejemplo, MATLAB® no admite instrucciones como patient(1:2).test(1:2,2:3), que intentan indexar en un campo en varios elementos del arreglo de estructuras.

Consideraciones Avanzadas sobre Estructuras

Punteros a Estructuras

La definición de un puntero a una estructura es una tarea simple, sin embargo, es en el manejo de la variable referenciada donde debemos centrar nuestra atención. Cuando definimos un puntero a una estructura, debemos tener bien claro que lo que hemos creado es un puntero y no una variable del tipo de estructura directamente. Es recién cuando asignamos una dirección válida al puntero cuando se crea la variable referenciada de tipo struct.

Esa forma de acceder al campo de la variable referenciada, aunque es correcta, es un poco forzada. Como se ve, la flecha lleva el puntero a la variable referenciada, de allí que el lenguaje define el operador -> (con el guión (-) y el signo mayor que (>), que semeja a una flecha), para llegar al campo de la variable referenciada.

Estructuras Autoreferenciadas

Una estructura autoreferenciada es una variable de tipo struct en la que uno o más de sus campos son punteros del mismo tipo que la estructura que lo define. La diferencia en este caso es que para definir los nodos de la lista usaremos estructuras en lugar de arreglos de punteros genéricos.

Uniones

Una unión es una estructura con características especiales. La diferencia radica en que cada uno de los campos definidos en ella comparten el mismo espacio de memoria. Como se puede apreciar, los campos comparten el mismo espacio de memoria.

Listas

Una de las principales características de los arreglos es la homogeneidad: todos los elementos que contienen deben ser del mismo tipo. Sin embargo, en muchos problemas resulta útil contar con alguna estructura de datos que permita agrupar objetos de diversos tipos. Esa es, justamente, la definición de una lista. Podemos imaginarla como una bolsa en la cual podemos meter todo tipo de objetos, incluyendo vectores, matrices y, por qué no, otras bolsas (es decir, bolsas dentro de una bolsa o listas dentro de una lista).

Todos los lenguajes de programación proveen algún tipo de estructura con estas características, aunque no todos las llaman igual. Otros posibles nombres con los que se conocen pueden ser tupla o agregado. En R se llaman listas o vectores recursivos. Para ser más rigurosos, una lista es un tipo especial de vector que agrupa punteros hacia distintos objetos.

Una lista lineal es un conjunto de elementos de un tipo dado que se encuentran ordenados, aunque pueden variar en número. Una lista enlazada es una estructura de datos fundamental que se utiliza para implementar otras estructuras de datos, como fue el caso de las pilas, las colas simples y las bicolas.

Usamos dobles corchetes [[ ]] para referenciar a cada objeto que forma parte de la lista. Además, si queremos indicar un elemento dentro de un objeto que forma parte de la lista, agregamos otro conjunto de corchetes como hacemos con vectores y matrices. Cada uno de los elementos de una lista puede tener un nombre propio.

Finalmente, consideremos la situación en la cual queremos aplicarle la misma función a cada uno de los elementos que integran una lista. Para esto podemos usar lapply() o sapply(), parientes de la función apply(). Ambas funciones le aplican la función elegida como segundo argumento (length()) a cada elemento de la lista indicada en el primer argumento.

tags: #declaración #de #arreglos #de #estructuras