2. ESTRUCTURAS BÁSICAS En el computador un conjunto (no vacío) de datos se almacenan en memoria; el área de memoria se denomina por el elemento Xk; esto es una celda, una unidad de memoria direccionable; también se llama nodo. El nodo está compuesto de diferentes campos, donde se guarda la información para las operaciones que se realizan. Ejemplo: Figura 2.1 Ejemplo de un nodo. struct mu{ char nom; char def; } mu1; Un campo es un área para almacenar datos. La dirección de una celda de varios campos es la dirección del primer campo. Normalmente, nos referimos a un nodo de múltiples valores o múltiples palabras como un bloque. Cuando un campo F de un nodo A contiene la dirección de otro nodo B, se dice que el campo F de A es un pointer a B (el campo F de A encadena B). Un pointer nulo (no encadena ningún campo) es designado por &. Los valores para una variable son dados al desarrollar una instrucción de asignación, ejemplo, x <- 3, x toma el valor de 3 ß <- acc, ß toma el valor de acc nom <- µ, nom toma el valor de µ uss -> nn, nn toma el valor de uss El valor de una variable, en cualquier momento, dentro de un algoritmo, es el valor más reciente asignado. Ejemplo: Figura 2.2 Ejemplo de nodos encadenados. struct car{ char nom; float val; int *suc; } car1; La notación nom(car) o car.nom designa el contenido del campo nom del nodo (celda) cuya dirección esta en la variable car, por lo tanto, car.nom = X1 , car.val = 3.1. El link designa la dirección del nodo encadenado a la determinada por car, así suc.car es la dirección al nodo encadenado de car, suc.car.nom = X2. Definición. Una estructura de datos es un conjunto de nodos, en donde se almacena información, en 18 especial datos, y la que se relaciona de acuerdo a ciertas características y/o propiedades que el usuario requiere para procesos que ha de realizar en y con la estructura. También, una estructura es una colección de variables, que pueden ser de tipos diferentes, agrupados bajo el mismo nombre. Las estructuras ayudan a la organización de los datos complejos, ya que permiten que a un grupo de variables relacionadas se les trate como una unidad en lugar de como entidades separadas. Cuando se define una estructura, se está definiendo esencialmente un tipo complejo de variable, compuesto por los elementos de la estructura. Se tienen estructuras lógicas y estructuras físicas. La estructura lógica la define el usuario en el nivel de análisis y diseño, al relacionar los elementos con lógica para satisfacer un requerimiento determinado. La estructura física corresponde a la forma en que a través de un lenguaje de programación se crea la estructura lógica, en memoria de computador. Una estructura de datos se dice homogénea cuando todos los datos elementales que la forman son del mismo tipo.1 En caso contrario se dice que la estructura es heterogénea. Son varias las operaciones que se efectúan sobre las estructuras de datos, y una vez establecidas se definen como funciones. Función constructora. Algoritmos y mecanismos que permiten construir una estructura. Asigna memoria o espacios dinámicamente. Función destructora. Algoritmos y mecanismos que desasignan memoria y liberan recursos del sistema. Función de acceso. Algoritmos y mecanismos a través de los cuales se llega a una estructura y sus elementos. Función de prueba. Algoritmos y mecanismos que prueban si la estructura posee ciertos elementos. Función de inserción. Algoritmos y mecanismos que permiten la inclusión de elementos en una estructura. Función de eliminación. Algoritmos y mecanismos que permiten la exclusión de elementos de una estructura. De acuerdo a la operacionalidad sobre o con los datos que se realiza en las estructuras, éstas se clasifican como: 1 Siempre que se utiliza un dato en un programa de computador debe estar determinado su tipo, para que el traductor sepa cómo tratarlo y almacenarlo. Luis Carlos Torres Soler Estructuras de Datos 19 -. Pila LIFO2 (Last Input Firts Output). Se conoce con el nombre de STACK; sólo puede agregarse en la cabeza de la pila, y en caso de borrar, solamente puede borrarse el último que ha entrado. -. Pila FIFO3 (First Input Firts Output). Se conoce con el nombre de COLA; como el nombre lo indica, se agrega en la cola de la pila y se borra en la cabeza. -. DOBLE COLA. Puede ingresarse y borrarse por la cabeza o por la cola. -. LISTA. Es una pila donde puede insertarse y borrarse en cualquier parte de la misma. Otras estructuras de datos que se trabajan son: a. b. c. d. e. Listas multiplemente encadenadas Árboles Tablas Archivos Bases de Datos -BD- (de la combinación y manejo adecuado de los archivos y tablas) Existen estructuras de datos de tipo estático y dinámico. Una estructura es estática porque siempre ocupa el mismo espacio en memoria. En las estáticas se tienen arreglos, pilas, tablas y archivos; en el tipo dinámico se tienen pilas encadenadas, listas y árboles. También se considera las estructuras de datos lineales y no lineales; en las no lineales se tienen árboles, listas y anillos. 2.1. Array (Arreglos) Un array (arreglo), también llamado matriz, es la estructura de datos más usual. Existe en todos los lenguajes de programación y en algunos es de las pocas estructuras de datos existentes. Igualmente, la memoria de un computador puede considerarse como una matriz lineal. Un array es una estructura de datos formada por una cantidad fija de datos de un mismo tipo, cada uno de los cuales tiene asociado uno o más índices que determinan de forma unívoca la posición del dato en el array. Cada índice es un dato de tipo subrango. Debemos imaginarnos un array como una estructura de celdas donde se puede almacenar valores. En general, al número de índices del array se le llama número de dimensiones del array. La dimensión de la formación está dada por los valores máximos de los índices, y el número total de elementos es el producto de estos valores máximos. 2 3 En español UEPS (último en entrar, primero en salir) En español PEPS (primero en entrar, primero en salir) Facultad de Ingeniería 20 Un array es una estructura de datos estática. Esto es, al definirlo se especifica el numero de elementos que lo constituyen. Esto lo emplea el traductor para reservar área de memoria. Cada elemento ocupa el mismo número de bytes. Una cadena de caracteres (string) es una estructura de datos formada por una secuencia de caracteres en un determinado orden. En una variable de tipo string se almacena un nombre, una dirección, la temperatura, ... Sobre datos de tipo string se realizan las siguientes operaciones:4 Concatenación: consiste en formar una cadena a partir de dos cadenas, yuxtaponiendo los caracteres de ambas. Extracción de subcadena: permite formar una cadena a partir de otra existente. Comparación de cadenas: se considera menor aquella en que el primer carácter en que difieren ambas es menor. Obtención de longitud: la longitud de una cadena es un dato de tipo entero, cuyo valor es el número de caracteres que contiene. Consideremos el siguiente problema: Una empresa recibe mensualmente información sobre las ventas de cada una de sus sucursales y, desea obtener un listado de aquellas, cuyas ventas superan el promedio de las mismas. Para dicho problema se pueden construir distintos algoritmos. Método 1. Para realizar esta tarea podrían leerse dos veces los datos de las sucursales: en la primera lectura, se determinará el promedio de las ventas y, una vez que este promedio sea conocido, puede realizarse la segunda lectura de las ventas, para determinar, cuáles tienen ventas superiores al promedio. Finalmente, se informará cuales sucursales, con sus correspondientes ventas cumplen con esta condición. Algoritmo ventas inicio ventas, promedio: real i: entero promedio <- 0, i<-0 MQ i<=3 leer ventas promedio <- promedio+ventas 4 Una cadena de caracteres y un array lineal pueden contener la misma información, pero son tipos de datos distintos. Representan objetos distintos y las operaciones sobre ellos son diferentes. Luis Carlos Torres Soler Estructuras de Datos i<- i+1 21 FMQ promedio=promedio/i i<-1 MQ i<=3 leer ventas SI ventas >=promedio TH escribir i, ventas FSI i<- i+1 FMQ FIN Si bien este algoritmo funciona, es ineficiente por el hecho de leer, dos veces, el mismo conjunto de datos de entrada. Método 2. Una forma alternativa de obtener los mismos resultados es el siguiente algoritmo: Algoritmo ventas inicio vent1, vent2, vent3, promedio: real leer vent1, vent2, vent3 promedio <- (vent1 + vent2, vent3)/3 SI vent1 >=promedio TH escribir vent1 FSI SI vent2 >=promedio TH escribir vent2 FSI SI vent3 >=promedio TH escribir vent3 FSI FIN Sin embargo, este algoritmo es válido, sólo, para tres sucursales ?Cómo plantear el algoritmo por ejemplo, para 100 sucursales? Método 3. Una forma más eficiente de resolver este problema consiste en reunir las ventas de las sucursales bajo un único nombre: venta5. Ahora se escribe el algoritmo como: Algoritmo ventas inicio venta: array[1..100] real 5 Se define un array con el número de sucursales posibles, es decir, las ventas de las sucursales se hallan en venta[1], venta[2], venta[3], ... Facultad de Ingeniería promedio: real i: entero promedio <- 0, i<-0 MQ i<=100 leer venta[i] promedio <- promedio+venta[i] i<- i+1 FMQ promedio=promedio/i i<-1 MQ i<=100 SI venta[i] >=promedio TH escribir i, venta[i] FSI i<- i+1 FMQ 22 FIN Cada componente de un array se denota, explícitamente, y es accedida directamente, mencionando el nombre del arreglo seguido de una expresión encerrada entre corchetes, a la que se llama índice del arreglo. Ejemplo. Escribir un algoritmo que ordene de menor a mayor los elementos de un arreglo de elementos enteros. El método a utilizar consiste en: a. Encontrar el menor elemento, entre los n, del array. b. Intercambiar el elemento encontrado con el primero del array c. Repetir esta operación con los n-1 restantes, seleccionando, el segundo elemento; proseguir con los n-2 elementos restantes, hasta que quede solamente el mayor valor. Algoritmo ordenar inicio X: array[1..10] entero i, j, min, valmin: entero i<-1 MQ i<=10 leer X[i] i<- i+1 FMQ i<-1 MQ i<=10 min <-i j<- i+1 MQ j<=10 SI X[j] < X[min] TH min <- j FSI Luis Carlos Torres Soler Estructuras de Datos j<- j+1 23 FMQ valmin <- X[min] X[min] <- X[i] X[i] <- valmin i <- i+1 FMQ i <- 1 MQ i <= 10 escribir X[i] FMQ FIN La composición de los nodos en las pilas y listas puede ser secuencial o encadenada; la limitación de memoria, el lenguaje utilizado, la cantidad de nodos que pueda tener, la composición de los mismos y el manejo determinan si es secuencial o encadenada. Una lista es una secuencia de n (>0) nodos; X1, X2, X3,..., Xn; cuyas propiedades estructurales esencialmente envuelve solamente las posiciones relativas de los nodos, como: a. X1 es el primer nodo. b. Para 1<k<n-1, Xk es precedido por Xk-1 y seguido por Xk+1 c. Xn es el último nodo. La simple y más natural manera para guardar una estructura secuencial dentro de un computador es colocar los nodos en localizaciones secuenciales, un nodo después de otro, así: loc.nodoj+1 = loc.nodoj +C donde C es el número de bytes por nodo, es decir, loc.Nj = l0 + j*C , siendo l0 la dirección base. Facultad de Ingeniería