Documentos de Académico
Documentos de Profesional
Documentos de Cultura
1
Estructuras autorreferenciadas
• Una estructura autorreferenciada contiene un miembro puntero que apunta a una
estructura del mismo tipo de estructura. Por ejemplo, la siguiente definición crea el tipo
struct nodo:
• La estructura nodo tiene dos miembros -el miembro entero data y el miembro puntero
nextPtr. El puntero nextPtr apunta a otro nodo. Esta estructura tiene el mismo tipo que
estamos definiendo, de ahí el término estructura autorreferenciada.
• El miembro nextPtr es un enlace que puede usarse para enlazar un struct nodo con otro
struct nodo. Enlazamos objetos estructurales autorreferenciados para formar listas, colas,
pilas y árboles.
2
Estructuras autorreferenciadas
• El siguiente diagrama muestra dos objetos de estructura autorreferenciada enlazados juntos
para formar una lista:
• La barra en el último nodo representa un puntero NULL, que indica que el nodo no apunta a
otro nodo. Un puntero NULL indica el final de una estructura de datos.
• No establecer el enlace del último nodo a NULL puede conducir a errores en tiempo de
ejecución.
3
Administración de memoria dinámica
• La creación y mantenimiento de estructuras de datos dinámicas que crecen y se reducen en
tiempo de ejecución requiere una gestión dinámica de la memoria, que tiene dos
componentes
4
Administración de memoria dinámica
Función malloc
• Para solicitar memoria en tiempo de ejecución, pasa a la función malloc el número de bytes a
asignar.
• Si tiene éxito, malloc devuelve un puntero void * a la memoria asignada. Recordemos que un
puntero void * puede ser asignado a una variable de cualquier tipo de puntero. La función
malloc se utiliza normalmente con sizeof.
• Por ejemplo, la siguiente sentencia determina el tamaño de un objeto struct node en bytes
con sizeof(struct node), asigna una nueva área en memoria de ese número de bytes y
almacena un puntero a la memoria asignada en newPtr:
5
Administración de memoria dinámica
• No se garantiza que la memoria esté inicializada, aunque muchas implementaciones la
inicializan por seguridad. Si no hay memoria disponible, malloc devuelve NULL.
Función free
• Cuando ya no necesites un bloque de memoria asignado dinámicamente, devuélvelo al
sistema inmediatamente llamando a la función free para liberar la memoria. De este modo,
se devuelve al sistema para su posible reasignación en el futuro.
6
Administración de memoria dinámica
• Después de liberar la memoria, establezca el puntero a NULL. Esto evita que se haga
referencia accidentalmente a esa memoria, que puede haber sido ya asignada para otro
propósito. No liberar la memoria asignada dinámicamente cuando ya no se necesita puede
hacer que el sistema se quede sin memoria prematuramente.
• Esto se llama a veces "fuga de memoria". Referirse a la memoria que ha sido liberada es un
error que típicamente causa que un programa se bloquee. Liberar memoria que no ha sido
asignada dinámicamente con malloc es un error.
• C también proporciona las funciones calloc y realloc para crear y modificar el tamaño de los
arreglos dinámicos. En los siguientes puntos se discutirán estas funciones.
7
Listas enlazadas
• Una lista enlazada es una colección lineal de objetos struct autoreferenciados, llamados
nodos, conectados por enlaces de punteros -de ahí el término lista "enlazada".
• Se accede a una lista enlazada a través de un puntero a su primer nodo y se accede a los
nodos siguientes a través de los miembros del enlace de puntero de los nodos.
• Los datos se almacenan dinámicamente en una lista enlazada creando cada nodo según sea
necesario. Un nodo puede contener cualquier tipo de datos, incluidos otros objetos struct.
• Las pilas y las colas también son estructuras de datos lineales. Pronto verás que son
versiones limitadas de las listas enlazadas.
8
Listas enlazadas
Arreglos vs Listas enlazadas
– Una lista enlazada es apropiada cuando el número de datos es imprevisible. Una lista enlazada es dinámica, por
lo que su longitud puede aumentar o disminuir según sea necesario. Los arreglos son estructuras de datos de
tamaño fijo (aunque se puede asignar y reasignar arreglos dinámicamente).
– Un arreglo puede ser declarado para contener más elementos que el número de datos esperados, pero esto
puede desperdiciar memoria. El uso de listas enlazadas y la asignación dinámica de memoria para estructuras de
datos que crecen y se reducen en tiempo de ejecución puede ahorrar memoria. Sin embargo, hay que tener en
cuenta que los punteros de los nodos de una lista requieren memoria adicional. Además, la asignación de
memoria dinámica conlleva la sobrecarga de las llamadas a funciones.
– Los arreglos de tamaño fijo pueden llenarse. Las listas enlazadas sólo se llenan cuando el sistema no tiene
suficiente memoria para satisfacer las solicitudes de asignación de almacenamiento dinámico.
– Las listas enlazadas pueden mantenerse ordenadas insertando cada nuevo elemento en el punto apropiado de
la lista. Insertar y borrar en un arreglo ordenado puede llevar mucho tiempo. Todos los elementos que siguen al
elemento insertado o eliminado deben ser desplazados adecuadamente.
9
Listas enlazadas
Los arreglos son más rápidos para el acceso directo a los elementos
• Los elementos de los arreglos se almacenan de forma contigua en la memoria. Esto permite el acceso
inmediato a cualquier elemento del arreglo.
10
Implementando listas enlazadas
11
Implementando listas enlazadas
Función insert
12
Implementando listas enlazadas
Función delete
13
Implementando listas enlazadas
Funciones isEmpty and printList
14
Implementando listas enlazadas
Ejercicio de listas enlazadas
• Elaborar un programa utilizando una lista enlazada que le permita al usuario administrar n
productos de una tienda con base en la siguiente información:
– Código (numérico)
– Descripción (alfanumérico),
– Precio (numérico con dos puntos decimales)
– Cantidad de productos en existencia
En este programa desarrolle las siguientes funciones para:
– Registrar un producto con base en el orden del código,
– Eliminar un producto con base en el código.
– Consultar por código los datos de un producto.
– Actualizar los datos de un producto.
– Mostrar todos los productos.
15
Pilas
• Una pila puede implementarse como una versión restringida de una lista enlazada. Se añaden
nuevos nodos y se eliminan los existentes sólo en la parte superior.
• Por esta razón, una pila se conoce como una estructura de datos de último en entrar,
primero en salir (LIFO).
16
Pilas
• El siguiente diagrama ilustra una pila con varios nodos. stackPtr apunta al elemento superior
de la pila. En estas figuras representamos las pilas y las listas enlazadas de forma idéntica.
• La diferencia entre ellas es que las inserciones y eliminaciones pueden ocurrir en cualquier
parte de una lista enlazada, pero sólo en la parte superior de una pila.
• Las funciones principales de una pila son push y pop. La función push crea un nuevo nodo y lo
coloca en la parte superior de la pila. La función pop elimina un nodo de la parte superior de
la pila, libera la memoria de ese nodo y devuelve el valor que se ha extraído.
17
Implementación de una pila
18
Implementación de una pila
19
Implementación de una pila
20
Implementación de una pila
21
Aplicaciones de las pilas
• Las pilas tienen muchas aplicaciones interesantes. Por ejemplo, cada vez que se hace una
llamada a una función, la función llamada debe saber cómo volver a su llamador, por lo que
la dirección de retorno se introduce en una pila.
• Las pilas soportan las llamadas a funciones recursivas de la misma manera que las llamadas
convencionales no recursivas. Las pilas contienen el espacio creado para las variables locales
automáticas en cada invocación de una función.
• Cuando la función vuelve a su llamador, el espacio para las variables automáticas de esa
función se saca de la pila, y estas variables ya no son conocidas por el programa. Los
compiladores también utilizan a veces las pilas en el proceso de evaluación de expresiones y
generación de código en lenguaje de máquina.
22
Colas
• Una cola es similar a la cola de la caja de un supermercado:
• Los nodos de la cola se eliminan sólo de su cabeza (frente) y se insertan sólo en su cola (parte
trasera).
• Por esta razón, una cola se conoce como una estructura de datos de primero en entrar, primero
en salir (FIFO). Las operaciones de inserción y eliminación se conocen como encolar y desencolar,
respectivamente.
– En las computadoras que tienen un solo procesador, sólo se puede atender a un usuario a la vez.
Las entradas para los demás usuarios se colocan en una cola. Cada entrada avanza gradualmente
hacia el frente de la cola a medida que los usuarios reciben el servicio. La entrada al frente de la
cola es la siguiente en recibir servicio.
23
Aplicaciones de las colas
– Del mismo modo, en los sistemas multinúcleo actuales, puede haber más programas en ejecución
que procesadores. Los programas que no se están ejecutando en ese momento se colocan en una
cola hasta que un procesador ocupado esté disponible. Cuando el trabajo de un programa se divide
en múltiples hilos capaces de ejecutarse en paralelo, podría haber más hilos que procesadores. Los
hilos que no se están ejecutando en ese momento tienen que esperar en una cola.
– Las colas también soportan la cola de impresión. Una oficina puede tener sólo una impresora.
Muchos usuarios pueden enviar documentos a imprimir en un momento dado. Cuando la impresora
está ocupada, los documentos adicionales se ponen en cola de impresión en la memoria o en el
almacenamiento secundario, al igual que el hilo de coser se enrolla en un carrete hasta que se
necesita. Los documentos esperan en una cola hasta que la impresora esté disponible.
– Los paquetes de información que viajan por redes de computadoras, como Internet, también
esperan en colas. Cada vez que un paquete llega a un nodo de la red, debe ser enrutado al
siguiente nodo de la red a lo largo del camino hacia su destino final. El nodo de enrutamiento
enruta un paquete a la vez, por lo que los paquetes adicionales se ponen en cola hasta que el
enrutador puede enrutarlos.
24
Representación de una cola
• El siguiente diagrama ilustra una cola con varios nodos. Observe los punteros separados de
la cabeza y la parte final de la cola.
• Al igual que con las listas y las pilas, no establecer el enlace del último nodo de la cola a
NULL puede conducir a errores lógicos.
25
Implementación de una cola
26
Implementación de una cola
27
Implementación de una cola
28
Implementación de una cola
29
Ejercicios de pilas y colas
• (Invertir las palabras de una frase) Escriba un programa que introduzca una línea de texto y utilice una pila para
imprimir la línea invertida.
• (Comprobador de palíndromos) Escriba un programa que utilice una pila para determinar si una cadena es un
palíndromo (es decir, la cadena se escribe de forma idéntica hacia adelante y hacia atrás). El programa debe ignorar
los espacios y la puntuación
• Realice un programa Agenda que almacene en una cola las actividades del día, el programa deberá permitir:
– Insertar una actividad.
– Borrar una actividad.
– Ver todas las actividades del día.
A demás de realizar estas funciones deberá crear una función para asignar memoria a la nueva actividad y otra
función que borre todos los elementos, esta última función se realiza para liberar toda la memoria asignada
dinámicamente. La estructura a utilizar es la siguiente:
– struct actividad
– {
– char act[50]; //Actividad a realizar...
– char hora[10]; //Hora en la que se realizara la actividad...
– struct actividad *siguiente; //Puntero al siguiente elemento...
– };
– typedef struct actividad agenda;
30
Listas doblemente enlazadas
• Una lista doblemente enlazada es un tipo más complejo de lista enlazada que contiene un
puntero al nodo siguiente y al anterior en la secuencia.
• Por lo tanto, consta de tres partes: datos, un puntero al siguiente nodo y un puntero al nodo
anterior, como se muestra en la siguiente figura:
31
Listas doblemente enlazadas
• El campo PREV del primer nodo y el campo NEXT del último nodo contendrán NULL.
• El campo PREV se utiliza para almacenar la dirección del nodo anterior, lo que nos permite
recorrer la lista en sentido inverso.
• Una lista doblemente enlazada requiere más espacio por nodo y operaciones básicas más
costosas.
• Sin embargo, una lista doblemente enlazada facilita la manipulación de los elementos de la
lista, ya que mantiene punteros a los nodos en ambas direcciones (hacia adelante y hacia
atrás).
• La principal ventaja de utilizar una lista doblemente enlazada es que hace que la búsqueda
sea doblemente eficiente.
32
Listas doblemente enlazadas
• Lista doblemente enlazada en la memoria:
33
Listas doblemente enlazadas
• Inserción de un nuevo nodo en una lista doblemente enlazada
34
Listas doblemente enlazadas
• Inserción de un nodo al principio de una lista doblemente enlazada
Nuevo nodo:
35
Listas doblemente enlazadas
• Inserción de un nodo al final de una lista doblemente enlazada:
Nuevo nodo:
• Utilizar una variable puntero PTR y hacer que apunte al primer nodo de la lista.
36
Listas doblemente enlazadas
• Inserción de un nodo después de un nodo dado (por ejemplo nodo con valor de 3) de una lista doblemente
enlazada:
Nuevo nodo:
• Utilizar una variable puntero PTR y hacer que apunte al primer nodo de la lista.
• Mover PTR hasta que la parte de datos de PTR = valor después del cual el nodo tiene que ser insertado.
37
Listas doblemente enlazadas
• Algoritmo para insertar un nuevo nodo después de un nodo dado de la lista doblemente
enlazada:
38
Listas doblemente enlazadas
• Inserción de un nodo antes de un nodo dado (por ejemplo nodo con valor de 3) de una lista doblemente
enlazada:
Nuevo nodo:
• Utilizar una variable puntero PTR y hacer que apunte al primer nodo de la lista.
• Mover PTR para que ahora apunte al nodo cuyos datos son iguales al valor antes del cual el nodo tiene
que ser insertado.
39
Listas doblemente enlazadas
• Algoritmo para insertar un nuevo nodo antes de un nodo dado de la lista doblemente
enlazada:
40
Listas doblemente enlazadas
• Eliminación de un nodo de una lista doblemente enlazada
41
Listas doblemente enlazadas
• Eliminación del primer nodo de una lista doblemente enlazada
42
Listas doblemente enlazadas
• Eliminación del último nodo de una lista doblemente enlazada
• Definir una variable puntero PTR que apunta al primer nodo de la lista.
• Liberar el espacio ocupado por el nodo apuntado por PTR y almacenar NULL en el campo NEXT
de su nodo precedente.
43
Listas doblemente enlazadas
• Algoritmo para eliminar el último nodo de la lista doblemente enlazada:
44
Listas doblemente enlazadas
• Eliminación del nodo posterior a un nodo dado en una lista doblemente enlazada (Supongamos
que queremos borrar el nodo que sucede a el nodo que contiene el valor de los datos 4.)
• Definir una variable puntero PTR que apunta al primer nodo de la lista.
• Mueve el PTR para que su parte de datos sea igual al valor después del cual el nodo tiene que
ser insertado.
45
Listas doblemente enlazadas
• Algoritmo para eliminar un nodo después de un nodo dado:
46
Listas doblemente enlazadas
• Eliminación del nodo anterior a un nodo dado en una lista doblemente enlazada (Supongamos
que queremos borrar el nodo que sucede a el nodo que contiene el valor de los datos 4.)
• Definir una variable puntero PTR que apunta al primer nodo de la lista.
• Mover el PTR hasta que su parte de datos sea igual al valor antes del cual el nodo tiene ser
eliminado.
47
Listas doblemente enlazadas
• Algoritmo para eliminar un nodo antes de un nodo dado:
48
Ejercicios de listas enlazadas, listas doblemente enlazadas, pilas y colas
• Ejecutar y corregir un error en una opción del programa propuesto en las páginas 194- 198 del
libro de Reema Thareja. Data Structures Using C. Oxford University Press, Inc., New York, NY,
USA. 2014.
• 12.6 (Concatenar listas) Escriba un programa que concatene dos listas enlazadas de
caracteres. El programa debe incluir la función concatenar que toma los punteros de ambas
listas como argumentos y concatena la segunda lista con la primera.
• 12.7 (Fusión de listas ordenadas) Escriba un programa que fusione dos listas ordenadas de
enteros en una única lista ordenada. La función fusionar debe recibir punteros al primer nodo
de cada una de las listas a fusionar y devolver un puntero al primer nodo de la lista fusionada.
• 12.8 (Inserción en una lista ordenada) Escriba un programa que inserte 25 enteros aleatorios
de 0 a 100 en orden en una lista enlazada. El programa debe calcular la suma de los elementos
y la media en coma flotante.
49
Ejercicios de listas enlazadas, listas doblemente enlazadas, pilas y colas
• 12.9 (Crear una lista enlazada y luego invertir sus elementos) Escriba un programa que cree una lista enlazada
de 10 caracteres y luego cree una copia de la lista en orden inverso.
• 12.10 (Invertir las palabras de una frase) Escriba un programa que introduzca una línea de texto y utilice una
pila para imprimir la línea invertida.
• 12.11 (Comprobador de palíndromos) Escriba un programa que utilice una pila para determinar si una cadena
es un palíndromo (es decir, la cadena se escribe de forma idéntica hacia adelante y hacia atrás). El programa
debe ignorar los espacios y la puntuación.
• 12.12 (Simulación de supermercado) Escriba un programa que simule la cola de salida de un supermercado. La
fila es una cola. Los clientes llegan en intervalos enteros aleatorios de 1 a 4 minutos. Además, cada cliente es
atendido en intervalos enteros aleatorios de 1 a 4 minutos. Obviamente, las tasas deben estar equilibradas. Si
la tasa media de llegada es mayor que la tasa media de servicio, la cola crecerá infinitamente. Incluso con tasas
equilibradas, la aleatoriedad puede provocar largas colas. Realice la simulación del supermercado durante un
día de 12 horas (720 minutos) utilizando el siguiente algoritmo:
1. Elija un número entero aleatorio entre 1 y 4 para determinar el minuto en que llega el primer cliente.
50
Ejercicios de listas enlazadas, listas doblemente enlazadas, pilas y colas
2. A la hora de llegada del primer cliente
Determine la hora de servicio del cliente (int aleatorio 1-4);
Comenzar a atender al cliente;
Programar la hora de llegada del siguiente cliente (int aleatorio 1-4 sumado a la hora actual).
Ahora ejecute su simulación durante 720 minutos y responda a cada una de las siguientes preguntas
51
Ejercicios de listas enlazadas, listas doblemente enlazadas, pilas y colas
• Elaborar un programa utilizando una lista doblemente enlazada que le permita al usuario
administrar n productos de una refaccionaria de autos con base en la siguiente información:
– Clave (numérico)
– Descripción (alfanumérico),
– Precio (numérico con dos puntos decimales)
– Cantidad de productos en existencia
En este programa desarrolle las siguientes funciones para:
– Registrar un producto con base en el orden del código,
– Eliminar un producto con base en el código.
– Consultar por código los datos de un producto.
– Actualizar los datos de un producto.
– Mostrar todos los productos.
52