PILA
Una pila
(stack en inglés) es una lista ordenada o estructura de datos en la que el modo
de acceso a sus elementos es de tipo LIFO (del inglés Last In First Out, último
en entrar, primero en salir) que permite almacenar y recuperar datos. Esta
estructura se aplica en multitud de ocasiones en el área de informática debido
a su simplicidad y ordenación implícita de la propia estructura.
Para el manejo
de los datos se cuenta con dos operaciones básicas: apilar (push), que coloca
un objeto en la pila, y su operación inversa, retirar (o desapilar, pop), que
retira el último elemento apilado.
En cada
momento solo se tiene acceso a la parte superior de la pila, es decir, al
último objeto apilado (denominado TOS, Top of Stack en inglés). La operación
retirar permite la obtención de este elemento, que es retirado de la pila
permitiendo el acceso al siguiente (apilado con anterioridad), que pasa a ser
el nuevo TOS. Por analogía con objetos cotidianos, una operación apilar
equivaldría a colocar un plato sobre una pila de platos, y una operación
retirar a retirarlo.
Las pilas
suelen emplearse en los siguientes contextos:
·
Evaluación de expresiones en notación postfija
(notación polaca inversa).
·
Reconocedores sintácticos de lenguajes
independientes del contexto.
·
Implementación de recursividad.
Declaraciones de tipos para manejar pilas en C
Los tipos que
definiremos normalmente para manejar pilas serán casi los mismos que para
manejar listas, tan solo cambiaremos algunos nombres:
typedef struct_nodo {
int dato;
struct_nodo
*siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Pila;
tipoNodo es el tipo para
declarar nodos, evidentemente.
pNodo es el tipo para declarar
punteros a un nodo.
Pila es el tipo para declarar
pilas.
Es evidente, a la vista del gráfico, que una pila es una
lista abierta. Así que sigue siendo muy importante que nuestro programa nunca
pierda el valor del puntero al primer elemento, igual que pasa con las listas
abiertas. Teniendo en cuenta que
las inserciones y borradores en una pila se hacen siempre en un extremo, lo que
consideramos como el primer elemento de la lista es en realidad el último
elemento de la pila.
OPERACIONES
Una pila cuenta con 2 operaciones imprescindibles: apilar
y desapilar, a las que en las implementaciones modernas de las pilas se suelen
añadir más de uso habitual.
·
Crear: se crea la pila vacia
(constructor).
·
Tamaño: regresa el número de elementos
de la pila (size).
·
Apilar: se añade un elemento a la pila
(push).
·
Desapilar: se elimina el elemento frontal
de la pila (pop).
·
Cima: devuelve el elemento que está
en la cima de la pila (top o peek).
·
Vacía: devuelve cierto si la pila está
sin elementos o falso en caso de que contenga uno (empty).
Tipos de Pilas
El tipo base
de la estructura FIFO (el primero en entrar es el primero en salir) es la cola
y la combinación de las operaciones de la pila y la cola es proporcionado por
el de que. Por ejemplo: el cambio de una pila en una cola en un algoritmo de
búsqueda puede cambiar el algoritmo de búsqueda en primera profundidad (en
inglés, DFS) por una búsqueda en amplitud (en inglés, BFS). Una pila acotada es
una pila limitada a un tamaño máximo impuesto en su especificación.
Pilas alojadas
en arreglos
Implementación
de pilas con arreglos: resulta conveniente el almacenamiento secuencial para el
tratamiento de pilas. Podemos tener una variable llamada TOPE que contenga el
índice donde está ubicado el tope de la pila. Cuando la pila está vacía, se
hace TOPE=0.
Por ejemplo: se puede definir una constante
llamada CANTELEMENTOS que tenga el valor máximo de elementos que podrá contener
la pila, un tope con la última posición, un valor a ser ingresado y el arreglo
mismo:
#define CANTELEMENTOS 10;
int tope= -1; /*inicializamos a
la variable tope con el valor -1 para que represente a la pila vacía porque el
1º elemento tiene índice 0.*/
int pila[CANTELEMENTOS];
int valor;
Para darte un ejemplo sencillo: supone que tienes una
pila de 10 platos. El primer plato de la pila será el último en quitarse y el
último plato de la pila será el primero en quitarse.
Un arreglo constituye el depósito de los elementos de la
pila. El rango del arreglo debe ser lo suficientemente amplio para poder
contener el máximo previsto de elementos de la pila. Un extremo del arreglo se
considera el fondo de la pila, que permanecerá fijo. La parte superior de la
pila, tope o cima, estará cambiando dinámicamente durante la ejecución del
programa. Además del arreglo, una variable entera nos sirve para tener en todo
momento el índice del arreglo que contiene el elemento tope. Las declaraciones,
procedimientos y funciones para representar el TAD pila, forman parte de la
unidad pila.
·
Max_elem=…(Dependerá de cada realización).
·
Tipo_elem=…(Tipo de los elementos de la pila).
·
Pila= Registro.
·
Elem= arreglo [1…Max_elem] de Tipo_elem;
·
Tope= entero; FinRegistro.
Implementación
de Procedimientos Recursivos mediante pilas
Un
procedimiento o función contiene tanto variables locales como argumentos
ficticios o parámetros. A través de los argumentos se transmiten datos en las
llamadas a los subprogramas, o bien, se devuelven valores al programa o
subprograma invocante. Además, el subprograma debe guardar la dirección de
retorno al programa que realiza la llamada. En el momento en que termina la
ejecución de un subprograma el control pasa a la dirección guardada.
Ahora, el
subprograma es recursivo, entonces además de la dirección de retorno, los
valores actuales de las variables locales y argumentos deben de guardarse ya
que se usarán de nuevo cuando el subprograma se reactive. Supongamos que se ha
llamado al subprograma P, que tiene llamadas a si mismo, es decir, es
recursivo. El funcionamiento del programa recursivo P será: ü se crea una pila
para cada argumento. ü se crea una pila para cada variable local. ü se crea una
pila para almacenar la dirección de retorno. Cada vez que se hace una llamada
recursiva a P, los valores actuales de los argumentos y de las variables
locales se meten en sus pilas para ser procesadas posteriormente. Asimismo,
cada vez que hay un retorno a P procedente de una llamada recursiva anterior,
se restauran los valores de variables locales y argumentos de la simas de la
pilas. Para la obtención de la dirección de retorno es de suponer que el
procedimiento P contiene una llamada recursiva en la sentencia N. Entonces
guarda en optra pila la dirección de retorno, que será la sentencia siguiente,
la N+1. De tal forma que cuando el nivel de ejecución del procedimiento P
actual termine, o sea, alcance la sentencia end final, usará dicha pila de
direcciones para volver al nuevo nivel de ejecución.
COLAS
Una cola
(también llamada fila) es una estructura de datos, caracterizada por ser una
secuencia de elementos en la que la operación de inserción push se realiza por
un extremo y la operación de extracción pop por el otro. También se le llama
estructura FIFO (del inglés First In First Out), debido a que el primer
elemento en entrar será también el primero en salir.
Representación de las Colas
Se las puede
representar por listas enlazadas o por arrays
C= Q (1), Q (2),…, Q (n).
En cualquier caso se necesitan
dos punteros
frente (f)
final(r)
y la lista o array de n
elementos (LONGMAX)
Las
operaciones que pueden realizar con una cola son:
·
Acceder al primer elemento de la cola.
·
Añadir un elemento al final de la cola.
·
Eliminar el primer elemento de la cola.
·
Vaciar una cola.
·
Verificar el estado de la cola: vacía o llena.
Operaciones
·
Crear: se crea cola vacía.
·
Encolar (añadir, entrar, insertar): se añade un
elemento a la cola. Se añade al final de esta.
·
Desencolar (sacar, salir, eliminar): se elimina el
elemento frontal de la cola, es decir, el primer elemento que entró.
·
Frente (consultar, front): se devuelve
el elemento frontal de la cola, es decir, el primer elemento que entró.
Cola Circulares
Una cola
circular o anillo es una estructura de datos en la que los elementos están de
forma circular y cada elemento tiene un sucesor y un predecesor. Los elementos
pueden cosultarse, añadirse y eliminarse únicamente desde la cabeza del anillo
que es una posición distinguida. Existen dos operaciones de rotaciones, una en
cada sentido, de manera que la cabeza del anillo pasa a ser el elemento
sucesor, o el predecesor, respectivamente, de la cabeza actual.
Colas Doblemente Enlazadas
Como ocurre
con toda representación estática, una de las principales desventajas es que hay
que prever un máximo de elementos, y de ese máximo no se puede pasar. La
realización de una cola mediante una lista enlazada permite ajustarse
exactamente al número de elementos de la cola. Esta implementación con las
listas enlazadas utiliza dos punteros que acceden a la lista, el puntero frente
y el puntero final. Cola implementada con listas enlazadas, el puntero final
referencia al último nodo que fue añadido. En esta representación no tiene
sentido la operación que indica si la cola está llena. Al ser una estructura
dinámica crece y decrece según las necesidades. La definición de cola usando
listas enlazadas serían:
·
Tipo_elto: (Tipo del campo información de cada
nodo).
·
Nodo: Registro.
·
Elto: Tipo_elto;
·
Sig: hNodo;
·
Fregistro; Cola:
·
Registro frente: hNoho;
·
final: hNodo; Fregistro;
Tipos de Colas
a)
Colas Circulares (anillos): en las que el
último elemento y el primero están unidos.
b)
Colas de Prioridad: En ellas, los
elementos se atienden en el orden indicado por una prioridad asociada a cada
uno. Si varios elementos tienen la misma prioridad, se atenderán de modo
convencional según la posición que ocupen. Hay 2 formas de implementación:
a.
Añadir un campo a cada nodo con su prioridad.
Resulta conveniente mantener la cola ordenada por orden de prioridad.
b.
Crear tantas colas como prioridades haya, y
almacenar cada elemento en su cola.
c)
Bicolas: son colas en donde los nodos
se pueden añadir y quitar por ambos extremos; se les llama DEQUE (Double Ended
QUEue). Para representar las Bicolas se puede hacer con un array ciruclar con
inicio y fin que apunten a cada uno de los extremos. Hay variantes:
a.
Bicolas de entrada restringida: son aquellas
donde la inserción sólo se hace por el final, aunque se puede eliminar al
inicio ó al final.
b.
Bicolas de salida restringida: son aquellas donde
sólo se elimina por el final, aunque se puede insertar al inicio y al final.
Aplicaciones de Colas
Las colas
también se utilizan en muchas maneras en los sistemas operativos para
planificar el uso de los distintos recursos de la computadora. Uno de estos
recursos es la propia CPU (Unidad Central de Procesamiento).
Si esta
trabajando en un sistema multiusuario, cuando le dice a la computadora que
ejecute un programa concreto, el sistema operativo añade su petición a su “cola
de trabajo”. Cuando su petición llega al frente de la cola, el programa
solicitado pasa a ejecutarse. Igualmente, las colas se utilizan para asignar
tiempo a los distintos usuarios de los dispositivos de entrada / salida (E/S),
impresoras, discos, cintas y demás. El sistema operativo mantiene colas para
peticiones de imprimir, leer o escribir en cada uno de estos dispositivos.
No hay comentarios:
Publicar un comentario