Nombre Password [ Regístrate ]

Pilas

 

* Definición
* Implementación mediante array
* Implementación mediante lista enlazada
* Otras consideraciones

 

Definición

Una pila es una estructura de datos de acceso restrictivo a sus elementos. Se puede entender como una pila de libros que se amontonan de abajo hacia arriba. En principio no hay libros; después ponemos uno, y otro encima de éste, y así sucesivamente. Posteriormente los solemos retirar empezando desde la cima de la pila de libros, es decir, desde el último que pusimos, y terminaríamos por retirar el primero que pusimos, posiblemente ya cubierto de polvo.

En los programas estas estructuras suelen ser fundamentales. La recursividad se simula en un computador con la ayuda de una pila. Asimismo muchos algoritmos emplean las pilas como estructura de datos fundamental, por ejemplo para mantener una lista de tareas pendientes que se van acumulando.

Las pilas ofrecen dos operaciones fundamentales, que son apilar y desapilar sobre la cima. El uso que se les de a las pilas es independiente de su implementación interna. Es decir, se hace un encapsulamiento. Por eso se considera a la pila como un tipo abstracto de datos.

Es una estructra de tipo LIFO (Last In First Out), es decir, último en entrar, primero en salir.

A continuación se expone la implementación de pilas mediante arrays y mediante listas enlazadas. En ambos casos se cubren cuatro operaciones básicas: Inicializar, Apilar, Desapilar, y Vacía (nos indica si la pila está vacía). Las claves que contendrán serán simplemente números enteros, aunque esto puede cambiarse a voluntad y no supone ningún inconveniente.

 

Implementación mediante array

Esta implementación es estática, es decir, da un tamaño máximo fijo a la pila, y si se sobrepasa dicho límite se produce un error. La comprobación de apilado en una pila llena o desapilado en una pila vacía no se han hecho, pero sí las funciones de comprobación, que el lector puede modificar según las necesidades de su programa.

- Declaración:

type
    tpila = Record
          Cima : Integer;
          Elementos : Array[1..MAX_PILA] of Integer;
    End;

Nota: MAX_PILA debe ser mayor o igual que 1.


- Procedimiento de Creación:

Procedure crear(Var pila : tpila);
begin
     pila.cima := 0
end;


- Función que devuelve verdadero si la pila está vacía:

Function vacia(Var pila : tpila) : Boolean;
begin
     vacia := pila.cima = 0
end;


- Función que devuelve verdadero si la pila está llena:

Function llena(Var pila : tpila) : Boolean;
begin
     llena := pila.cima = MAX_PILA
end;


- Procedimiento de apilado:

Procedure apilar(Var pila : tpila; elem : integer);
begin
     Inc(pila.cima);
     pila.elementos[pila.cima] := elem
end;


- Procedimiento de desapilado:

Procedure desapilar(Var pila : tpila; Var elem : integer);
begin
     elem := pila.elementos[pila.cima];
     dec(pila.cima)
end;


Programa de prueba:

Var
   pila : tpila;
   elem : Integer;
Begin
     crear(pila);
     if (vacia(pila)) then writeln('Pila vacia');
     apilar(pila, 0);
     desapilar(pila, elem)
end.

 

Puesto que son muy sencillos, el usuario puede decidir implementar una pila 'inline', es decir, sin usar procedimientos ni funciones, lo cual aumentará el rendimiento a costa de una cierta legibilidad. Es más, los problemas que aparecen resueltos en esta web en general utilizan las pilas con arrays de forma 'inline'. Además, esta implementación es algo más rápida que con listas enlazadas, pero tiene un tamaño estático.

 

Implementación mediante lista enlazada

Para hacer la implementación se utiliza una lista con cabecera ficticia (ver apartado de listas). Dado el carácter dinámico de esta implementación no existe una función que determine si la pila está llena. Si el usuario lo desea puede implementar un análisis del código devuelto por la función de asignación de memoria.

- Declaración:

Type
    tpila = ^Rec;
    Rec = Record
        clave : Integer;
        sig : tpila;
    End;

- Procedimiento de creación:

Procedure crear(Var pila : tpila);
begin
  new(pila);
  pila^.sig := NIL
end;

- Función que devuelve verdadero si la pila está vacía:

Function vacia(pila : tpila) : boolean;
begin
  vacia := pila^.sig = NIL
end;


- Procedimiento de apilado (apila al comienzo de la lista):

Procedure apilar(pila : tpila; elem : Integer);
Var
  nuevo : tpila;
Begin
  New(nuevo);
  nuevo^.clave := elem;
  nuevo^.sig := pila^.sig;
  pila^.sig := nuevo
End;

- Procedimiento de desapilado (desapila del comienzo de la lista):

Procedure desapilar(pila : tpila; Var elem : Integer);
Var
  aux : tpila;
Begin
  aux := pila^.sig;
  elem := aux^.clave;
  pila^.sig := aux^.sig;
  dispose(aux)
End;


Programa de prueba:

Var
  pila : tpila;
  elem : Integer;
Begin
  crear(pila);
  if (vacia(pila)) then writeln('Pila vacia!');
  apilar(pila, 1);
  desapilar(pila, elem)
end.

Ver pilasle.pas para tener una implementación completa con lista enlazada.

En este caso, hacerlo 'inline' puede afectar seriamente la legibilidad del programa.

 

Otras consideraciones

- ¿Cuantos elementos hay apilados?

En algunos casos puede ser interesante implementar una función para contar el número de elementos que hay sobre la pila. En la implementación con arrays esto es directo. Si se hace sobre listas enlazadas entonces hay que hacer alguna pequeña modificación sobre la declaración e implementación:

Lista = ^Rec;
Rec = Record
    clave : Integer;
    sig : Lista;
End;
tPila = Record
    numero_elems : Integer;
    cima : Lista;
End;

Los detalles de la implementación no se incluyen, pues es sencilla.


- ¿Cómo vaciar la pila?

En el caso de la implementación con array es directo, basta con inicializar la cima al valor de vacío. Si es una lista enlazada hay que ir borrando elemento a elemento (o desapilarlos todos). Los detalles se dejan para el lector.

 

Elegir entre implementación con listas o con arrays.

El uso del array es idóneo cuando se conoce de antemano el número máximo de elementos que van a ser apilados y el compilador admite una región contigua de memoria para el array. En otro caso sería más recomendable usar la implementación por listas enlazadas, también si el número de elementos llegase a ser excesivamente grande.

La implementación por array es ligeramente más rápida. En especial, es mucho más rápido a la hora de eliminar los elementos que hayan quedado en la pila. Por lista enlazada esto no es tan rápido. Por ejemplo, piénsese en un algoritmo que emplea una pila y que en algunos casos al terminar éste su ejecución deja algunos elementos sobre la pila. Si se implementa la pila mediante una lista enlazada entonces quedarían en memoria una serie de elementos que es necesario borrar. La única manera de borrarlos es liberar todas las posiciones de memoria que le han sido asignadas a cada elemento, esto es, desapilar todos los elementos. En el caso de una implementación con array esto no es necesario, salvo que quiera liberarse la región de memoria ocupada por éste.

 


© (2001-2008) ALGORITMIA.NET - Política de privacidad