Sei sulla pagina 1di 29

Aplicaciones

de las Pilas

Gabriel Amigo Gmez

1. DEFINICIN DE PILA.
OPERACIONES
DEFINICIN: Una pila es una lista tal que las inserciones, eliminacioes y
lecturas de elementos solo se pueden realizar en una posicin llamada cima o
tope de la pila.
Las operaciones fundamentales en una pila son:
METER (en la pila): Inserta un elemento en la cima de la pila.
SACAR (de la pila): Elimina el elemento que ocupaba la posicin cima.
El elemento que haba sido insertado inmediatamente antes que el
eliminado pasa a la posicin cima.
CIMA (de la pila): Devuelve el elemento que ocupa la posicin cima.
(Distinguir CIMA como funcin sobre una pila de cima como
primera posicin de una pila.)

En una pila no se puede acceder a otra posicin que no sea la cima de la


pila, por tanto no se puede leer o modificar una posicin arbitraria de la
pila, ni hacer bsquedas ni nada que implique manejar otra posicin
distinta de cima sin modificar la pila.
Por esta razn las pilas tambin se conocen como listas LIFO (last in, first
out), ya que el ltimo elemento en entrar ser el primero en salir.

2. IMPLEMENTACIN DE PILAS
2.1 CON VECTORES
2.2 CON LISTAS ENLAZADAS
2.1 PILAS USANDO VECTORES
Para implementar pilas usando vectores o arreglos es necesario saber a
priori cul va a ser el nmero mximo de elementos que se van a poder
meter en una pila. Llammoslo num_max.
Declaracin del tipo pila (usando vectores) :
ELEMENTO=T;
PILA=registro de
tope: numrico;
arreglo: vector[1..num_max] de ELEMENTO;
fin registro;

tope va a corresponder a la posicin en el vector del ultimo elemento


insertado en la lista, o sea va a apuntar en todo momento al elemento cima.
As pila.tope=1 querr decir que la pila est llena mientras que
pila.tope=num_max + 1 querr decir que est vaca.
Esta implementacin no es apropiada cuando no se conoce el nmero
mximo de elementos que puede contener la pila porque se podran
necesitar ms posiciones de las existentes en el vector y producira un error.
Asimismo se puede desaprovechar mucha memoria si se define una pila
con un vector muy grande y luego se insertan pocos elementos.
La ventaja de esta implementacin es la rapidez con la que se realizan las
operaciones.

2.2 PILAS USANDO LISTAS ENLAZADAS


A diferencia de la cabecera de una lista usual, la cabecera de una pila no va
a ser un registro que incluya el nmero de nodos y punteros al primer y
ltimo elemento, sino que va a ser simplemente un puntero que apunta al
primer nodo.
Por eso, abusando de notacin podemos identificar una pila con su
cabecera.
Declaracin del tipo pila (usando listas enlazadas):
ELEMENTO=T;
NODO= registro de
info: ELEMENTO;
sgte: puntero a NODO;
fin registro;
PILA=puntero a NODO;

3. IMPLEMENTACIN DE
OPERACIONES SOBRE PILAS EN C
3.1 PILAS CON VECTORES
3.2 PILAS CON L. ENLAZADAS
Esta ser la implementacin en C de las pilas y de las operaciones METER,
SACAR, CIMA, VACA Y LLENA.

3.1 PILAS CON VECTORES


IMPLEMENTACIN DE PILA:
#define tam_max 20 /*el tamao maximo sera 20. se puede cambiar*/
typedef char elemento; /*va a ser una pila de caracteres*/
typedef struct {
int tope;
elemento v[tam_max];
} pila;
El tipo elemento variar dependiendo del programa, as como tam_max.
OPERACIONES:
VACA:
int vacia(pila1)
pila pila1;
{
if(pila1.tope==tam_max){
return 1;
}
else{
return 0;
}
}/*FIN VACIA*/
Esta funcin devuelve 1 si la pila est vaca y 0 si no lo est.
LLENA:
int llena(pila1)
pila pila1;
{
if((pila1.tope)==0){
return 1;

}
else{
return 0;
}
}/*FIN LLENA*/
Esta funcin devuelve 1 si la pila est llena y 0 si no lo est.
SACAR:
int sacar(punt_pila)
pila *punt_pila;
{
int vacia();
int valor_vacia;
valor_vacia=vacia(*punt_pila);
if(valor_vacia==1){
return 0;
}
else{
(*punt_pila).tope=(*punt_pila).tope+1;
return 1;
}
}/*FIN SACAR*/
Esta funcin elimina el elemento cima de la pila y devuelve 1 si la pila no
est
vaca y simplemente devuelve 0 si la pila est vaca. (Aplicar SACAR a
una
pila vaca la deja igual).
METER:
int meter(lo_que_meto,punt_pila)
elemento lo_que_meto;
pila *punt_pila;
{
int llena();
int copia_tope;
int valor_llena;
valor_llena=llena(*punt_pila);
if(valor_llena==1){
return 0;
}
else{
copia_tope=(*punt_pila).tope;
(*punt_pila).v[copia_tope-1]=lo_que_meto;
6

(*punt_pila).tope=copia_tope-1;
return 1;
}
}/*FIN METER*/
Esta funcin mete el elemento lo_que_meto en la pila y devuelve 1 si no
est
vaca y simplemente devuelve 0 si est llena.
CIMA:
elemento cima(pila1) /*1 hay q asegurarse d q no est vaca*/
pila pila1;
{
int vacia();
int copia_tope;
if(vacia(pila1)==0){ /*si no esta vacia se procede*/
copia_tope=pila1.tope;
return pila1.v[copia_tope];}
else{
printf("\n Error. Has aplicado la funcion cima a una pila vacia\n");
return pila1.v[1];}/*esto ultimo es absurdo, pues la pila esta vacia, pero te
ahorra un warning al compilar*/
}/*FIN CIMA*/
Esta funcin devuelve el elemento cima si la pila no est vaca y devuelve
un elemento de tipo elemento si est vaca dando un mensaje de error. Por
eso hay que asegurarse de que la pila no est vaca antes de llamar a
CIMA

3.2 PILAS CON L. ENLAZADAS


IMPLEMENTACIN DE PILA:
typedef char elemento;/*defino elemento como char. se puede cambiar*/
typedef struct NODE{
/*defino el tipo nodo como registro de info y sgte*/
elemento info; /*en ppio las pilas seran de char, pero esto se puede
cambiar*/
struct NODE *sgte;
};
typedef struct NODE nodo;
typedef nodo *pila; /*defino el tipo pila como puntero a nodo*/
El tipo elemento variar segn el programa.
OPERACIONES:
VACA:
int vacia(pila1)
pila pila1;
{
if (pila1==NULL) return 1;
else return 0;
}/*FIN VACIA*/
Vaca devuelve 1 si la pila est vaca y 0 si no lo est.
SACAR:
int sacar(punt_pila)
pila *punt_pila;
{
int vacia();
pila aux_pila;
if(vacia(*punt_pila)==1){
return 0;
}
else{ /* (*punt_pila)es igual a pila1, q es un puntero al 1er nodo, luego
quiero modificar su contenido: */
aux_pila=(*(*punt_pila)).sgte;
free(*punt_pila);
*punt_pila=aux_pila;
return 1;
}
}/*FIN SACAR*/

Sacar saca un elemento de la pila si no est vaca devolviendo 1 o devuelve


0 si est vaca.
METER:
int meter(lo_que_meto,punt_pila)
elemento lo_que_meto;
pila *punt_pila;
{
pila aux_pila;
aux_pila=*punt_pila; /*asi me hago una copia de pila1 en aux_pila*/
*punt_pila=(nodo*)calloc(1,sizeof(nodo)); /* pila1=*punt_pila */
if(*punt_pila==NULL){
printf("\n Error. No se puede reservar mas espacio.");
return 0;
}
else{ /*se ha podido reservar espacio para un nodo: se procede a meter*/
(*(*punt_pila)).info=lo_que_meto; /* (**punt_pila) apunta al 1er nodo*/
(*(*punt_pila)).sgte=aux_pila; /*para q el 1er nodo apunte al q ahora es el
2*/
return 1;
}
}/*FIN METER*/
Meter mete lo_que_meto en la pila en caso de que no est llena
devolviendo un 1 o da un mensaje de error y devuelve un 0 en caso de que
no haya ms espacio en memoria para otro nodo.
CIMA:
elemento cima(pila1)
pila pila1;
{
int vacia();
if(vacia(pila1)==0){/*no vacia*/
return ((*pila1).info);}
else{
printf("\n Error. Has aplicado la funcion cima a una pila vacia\n");
return ((*pila1).info);}/*esto ultimo es absurdo, pues la pila esta vacia, pero
te ahorra un warning al compilar*/} /*FIN VACA*/
Cima devuelve el elemento cima de una pila no vaca. Si se aplica sobre
una funcin vaca el programa aborta, as que hay que asegurarse antes
de ejecutarla.

4. ELIMINACIN DE LA
RECURSIN. TORRES DE HANOI.
Cuando se hace una llamada a una funcin el compilador debe guardar en
alguna parte el valor que tienen todas las variables antes de entrar en la
funcin, pues de lo contrario estos valores podran ser sobreescritos.
Cada coleccin de variables que se guardan antes de hacer una llamada se
llama registro de activacin.
Ejemplo:
El factorial recursivo:
main(){
int n, factorial();
scanf(%d,&n);
printf(Este es el factorial de %d: %d,n,factorial(n));}
int factorial(int n){
if(n==1) return 1; /*caso base*/
else return (n*factorial(n-1));}
Supongamos que le damos inicialmente n=3. Al entrar por primera vez en
factorial es necesario que guarde ese 3 en alguna parte. Lo va a guardar en
un registro de activacin.
Como la informacin que hay en un registro de activacin no va a poder ser
usada hasta que la llamada correspondiente haya terminado, la estructura de
datos pila es muy adecuada para almacenar los registros de activacin:
Segn se van haciendo llamadas, se meten registros de activacin en la pila
de forma que los registros de activacin correspondientes a llamadas ms
internas estarn ms arriba en la pila que los correspondientes a llamadas
ms externas.
Ejemplo:
Factorial de 3.
Partimos de una pila de registros de activacin vaca y una variable entera
auxiliar que vamos a llamar RF (registro de la funcin) y que va a ir
guardando los sucesivos valores provisionales de la funcin factorial.
Llamamos por primera vez a factorial() con n=3, luego metemos un 3 en la
pila (figura b). Como no es el caso base se vuelve a llamar a factorial() con
n=2. Se mete un 2 en la pila (figura c). A continuacin se llama a factorial()
con n=1 (figura d). En este punto llegamos a return 1, luego metemos un

10

1 en RF y sacamos un registro de la pila (pues la funcin factotrial(1) ya ha


terminado) (figura e).

Se multiplicar entonces el 2 de la cima de la pila por RF (que no va a ser


otra cosa que factorial(1), almacenando el resultado en RF y sacando
despus el 2 de la pila (figura f).
A continuacin se multiplica el 3 de la cima por RF (factorial(2)) quedando
la pila vaca y un 6 en RF (figura g). Entonces se devuelve el control al
programa principal quedando la pila vaca y un 6 en RF (figura h).

ELIMINACIN DE LA RECURSIN DE
COLA.
Se dice que un algoritmo recursivo presenta recursin de cola o tail
recursion cuando la llamada recursiva tiene lugar en la ltima lnea del
algoritmo.
Ejemplo:
void funcion_recursiva(param_1,....,param_m) {
declaracin de variables;
if (caso base){
sentencia_base_1;
....
sentencia_base_r;
}
else{
sentencia 1;
....
sentencia n;
funcion_recursiva(param_1,....,param_m);
}
}

11

ltima lnea

funcion_recursiva presenta recursin de cola.


En el caso de que la recursin sea recursin de cola, es fcil de eliminar,
pues equivale a un esquema while:
void funcion_recursiva(param_1,....,param_m) {
declaracin de variables;
while (no se satisfacen las condiciones del caso base){
sentencia 1;
....
sentencia n;
}
sentencia_base_1;
....
sentencia_base_r;
}

TORRES DE HANOI ELIMINANDO LA


RECURSIN.
El algoritmo recursivo que habamos visto en clase para el problema de las
torres de Hanoi es el siguiente:
void mover( int n, char O, char A, char D){/*va a mover de 'O' a 'D' */
if(n==1) { /* caso basico */
printf ("\n mover de %c a %c", O,D);}
else {
mover( n-1,O ,D, A);
printf ("\n mover de %c a %c", O,D);
mover (n-1, A, O, D);
}
}
Cada vez que se llama a mover, si no estamos en el caso base, mover va a
llamarse otras dos veces, haciendo un printf entre estas dos llamadas.
El siguiente esquema muestra las llamadas a mover si partimos de 2 discos:

12

Vemos que resulta un rbol binario.


Los argumentos de la funcin mover son: la altura de la torre a considerar
(n) y las letras que corresponden en cada momento a las torres origen,
auxiliar y destino (O,A,D). Por tanto estos cuatro datos han de ser
guardados en un registro de activacin cada vez que se hace una nueva
llamada a mover.
Asimismo hay que guardar el nmero de llamadas que ha hecho mover (0,
1 2), pues en funcin de esto se llama otra vez a mover o se devuelve el
control a la funcin anterior. Lo guardaremos en una variable entera
num_hijos.
Luego cada registro de activacin va a contener dos variables enteras y tres
de tipo carcter: altura, num_hijos, caracter1, caracter2, caracter3.
El algoritmo que elimina la recursin del algoritmo original va a recorrer
ordenadamente el rbol metiendo registros de activacin en una pila a
medida que se profundiza en el rbol y sacndolos a medida que se sube a
un nivel ms prximo a la raz. A la vez que hace esto, muestra por pantalla
los movimientos correspondientes. El algoritmo termina cuando la pila se
queda vaca, lo que significa que se ha devuelto el control al programa
principal.
El recorrer ordenadamente el rbol es un proceso iterativo, con lo que la
recursin queda eliminada.
La implementacin de pila ms adecuada es con vectores porque si
partimos de una torre con n discos, al llegar al caso base la pila tendr n
registros de activacin y ser el momento en el que ms llena est.
De esta forma definiendo la pila con un vector de n posiciones no nos
quedaremos sin espacio.

13

5. AJUSTE DE PARNTESIS,
CORCHETES Y LLAVES
Otra aplicacin de las pilas consiste en la revisin de programas para
buscar errores.
Por ejemplo en C todo parntesis, llave o corchete de apertura debe tener su
correspondiente smbolo de clausura
As una expresin con 10 parntesis de apertura y 9 de clausura no puede
ser vlida. Tampoco se admiten expresiones de este estilo: ( [ ) ] , { [ } ].
Se puede realizar un programa que, dado un fichero en C, nos diga si los
parntesis, corchetes y llaves estn bien anidados.
El algoritmo funciona as:
Partimos de una pila de caracteres vaca. Se leen caracteres del fichero uno
a uno y segn lo que sean, as se tratan:
a) Si leemos un caracter que no sea un parntesis, un corchete o una llave
entonces no hacemos nada y pasamos al siguiente carcter.
b) Si el caracter es uno de apertura: ( , [ { entonces lo metemos en la
pila.
c) Si el carcter es uno de clausura: ), ] } miramos la cima de la pila y si
es el correspondiente smbolo de apertura, se saca de la pila y pasamos al
siguiente carcter. Si la cima no fuese el smbolo de apertura
correspondiente, entonces se mete el carcter en la pila.
De esta forma, al terminar de leer el fichero sabremos que los parntesis,
corchetes y llaves estn bien anidados si y slo si la pila ha quedado vaca.
Este algoritmo tiene un inconveniente: los parntesis, corchetes y llaves
deben estar PERFECTAMENTE anidados, de forma que un comentario de
este estilo provocara que un trozo de cdigo bien hecho se interpretase
como un trozo con errores:
/*este comentario se carga el programa: ( [ ) ]*/
//este comentario tambin {{
De la igual forma una expresin como esta tambin sera mal interpretada:
printf(Esto esta bien pero dara fallo: %c,));
Luego hay que asegurarse de que al programa que encuentra errores se le
pase un fichero sin comentarios (o bien hechos) y sin utilizar los smbolos
(, ), [, ], {, } como caracteres (o utilizados de forma que no den error).
La implementacin ms lgica de pila para este programa es la que usa
listas enlazadas, pues la longitud del fichero puede ser muy variable y una
implementacin con vectores podra quedarse corta o pasarse de larga.

14

6. EVALUACIN DE EXPRESIONES
EN NOTACIN POSFIJA
LA NOTACIN POSFIJA:
1+(2*(9-3)) una expresin con la notacin usual o infija.
La notacin posfija es otra notacin en la cul no existen parntesis ni
jerarqua en las operaciones. La expresin anterior en notacin posfija sera
as:
93-2*1+
Quiere decir lo siguiente: el primer operador es la resta, luego va a restar
los dos nmeros anteriores: 9 y 3. Entonces el bloque 9 3 sera
equivalente a un 6:
62*1+
El siguiente operador es un *, luego se multiplican los dos nmeros
anteriores: 6 y 2. Entonces el bloque 6 2 * sera equivalente a 12:
12 1 +
El siguiente operador es +, luego se suman los dos nmeros anteriores:12 y
1.Entonces el resultado es 13.
Vemos que hacemos lo mismo que haramos en notacin infija y no hemos
tenido que acudir a parntesis ni a jerarqua de operaciones. Por eso la
evaluacin de expresiones posfijas es muy fcil de implementar.
Notacin infija
2*(3+8/(6-4))
3+2*7-1
1*2*3*4+5

Notacin posfija
23864-/+*
327*+112*3*4*5+
ejemplos de expresiones
EVALUACIN DE EXPRESIONES EN NOTACIN POSFIJA:
Otra aplicacin de las pilas es la evaluacin de expresiones en notacin
posfija:
Disponemos de una expresin en notacin posfija. Supongamos que, por
ejemplo, est almacenada en un fichero. Usaremos una pila de reales.
El algoritmo que evala la expresin har lo siguiente:
Leemos los datos del fichero uno a uno y los tratamos segn su tipo:
a) Es un real. Lo metemos en la pila.
b) Es un operador. Sacamos 2 nmeros reales de la pila y aplicamos el
operador sobre ellos. Metemos el resultado en la pila.
(Si la operacin es / entonces el elemento que antes hubiese
entrado en la pila ser el que aparezca a la izquierda del operador.
15

Por ejemplo, si tenemos la expresin 7 5 -, el 7 entra antes que el 5


en la pila, luego se har la operacin 7-5 y no la 5-7.)
En resumen, se trata de recorrer el fichero y cada vez que encontremos un
operador se lo aplicamos a los dos nmeros anteriores hasta que se termina
el fichero. Entonces el n real que quede en la pila ser el resultado.
Es difcil encontrarse con expresiones aritmticas muy largas as que
usando la implementacin de pila con vectores con un vector de unas 20
posiciones no es probable encontrar errores, pero si se manejan expresiones
muy largas la implementacin de listas enlazadas dar ms seguridad.

16

7. CONVERSIN DE NOTACIN
INFIJA A POSFIJA
Se pude transformar una expresin con notacin infija en su
correspondiente con notacin posfija utilizando pilas para ello.
Introduciremos una expresin en notacin infija y queremos escribir su
equivalente posfija en un fichero destino, por ejemplo.
El algoritmo que hace esto funciona as:
Tenemos una pila de caracteres, inicialmente vaca, en la que vamos a
meter los operadores.
Pedimos nmeros y operadores de uno en uno y segn su tipo as los
tratamos:
a) Es un n: Lo escribimos directamente en el fichero destino.
b) Es un operador: Si la pila est vaca, lo metemos en la pila.
Si la pila no est vaca y la cima de la pila es un operador de menor
prioridad, entonces tambin lo metemos en la pila.
Si la cima de la pila es un operador de mayor o igual prioridad,
entonces sacamos operadores de la pila y los escribimos en el fichero
destino hasta que en la cima haya un operador de menor prioridad o
un parntesis de apertura o hasta que la pila quede vaca. Entonces
metemos el operador en la pila.
De esta forma nos aseguramos de que las operaciones con mayor
prioridad se realizan anteriormente, pues sus operadores son los que
antes salen de la pila.
c) Es un parntesis:
-Es de apertura: se mete en la pila. Slo se puede sacar de la pila
cuando se encuentra un ).
-Es de clausura: se van sacando operadores de la pila y se escriben en
el fichero hasta que se encuentra (. Entonces se saca ( y se
contina el proceso.
De esta forma aseguramos que las operaciones contenidas en un
parntesis van a ser agrupadas.
Al terminar este proceso sacamos uno a uno los operadores que pudieran
quedar en la pila y los escribimos en el fichero destino.
Al igual que en la aplicacin anterior, dependiendo de la longitud de las
expresiones que se vayan a manejar, convendr utilizar una u otra
implementacin de pila.

17

Ejemplo:
Tenemos la expresin 3-36/(5+1)
El primer dato es un 3, as que lo mete en el fichero. Luego encuentra un -.
Va quedando as:
Pila
Fichero de salida
3
Ahora lee un 36 y lo escribe en el fichero. Al leer /, mira la cima de la pila.
Como la cima de la pila es un -, que es de menor prioridad, mete el / en la
pila:
Pila
Fichero de salida
/
3 36
Despus lee un (, que siempre se mete en la pila. Luego lee un 5 y lo
escribe en el fichero:
Pila
Fichero de salida
(
3 36 5
/
Ahora encuentra un +. Como la cima de la pila es (, que solo puede ser
sacado al encontrar ), mete el + en la pila.
Entonces lee 1 y lo escribe en el fichero:
Pila
Fichero de salida
+
3 36 5 1
(
/
Encuentra un ) luego va sacando operadores de la pila hasta encontrar un
(: Saca + y lo escribe en el fichero y luego saca )
Pila
Fichero de salida
/
3 36 5 1 +
Ya no quedan elementos que leer as que saca los operadores que quedaban
en la pila de uno en uno y los escribe en el fichero:
Pila
Fichero de salida
3 36 5 1 + / Combinando esta aplicacin con la anterior, tenemos una calculadora
bsica que admite el uso de parntesis y respeta la jerarqua de operaciones.

18

TORRES DE HANOI EN C:
/*TORRES DE HANOI ELIMINANDO RECURSIN*/
#include<stdio.h>
#define tam_max 20
typedef struct{
int altura; /*altura de la torre a considerar*/
int num_hijos; /*n de hijos a los que ha llamado la funcin recursiva*/
char caracter1,caracter2,caracter3;
} elemento;
/*cada elemento de la pila va a ser un registro elemento*/
/*defino el tipo pila usando vectores:*/
typedef struct {
int tope;
elemento v[tam_max];
} pila;
main(){
int n,vacia(),sacar(), meter();
pila pila1, *punt_pila;
elemento registro_aux, cima(), crear_registro();
pila1.tope=tam_max;
punt_pila=&pila1;
printf(" TORRES DE HANOI ELIMINANDO LA RECURSION\n");
do{
printf("\n Dame el numero de discos de la torre: ");
scanf("%d",&n);
if (n<=1) printf("\n Debe ser mayor que 1\n");
}while(n<=1);
registro_aux.altura=n; /*el primer elemento de la pila va a ser siempre este*/
registro_aux.num_hijos=0;
registro_aux.caracter1='O';
registro_aux.caracter2='A';
registro_aux.caracter3='D';
meter(registro_aux,punt_pila);
/*ahora entro en un bucle que, dependiendo de lo que haya en la cima
de la pila hace una cosa u otra*/
while(vacia(pila1)==0){
if(cima(pila1).altura==1){/*llego al caso base*/
printf("\n Mover de %c a %c\n",cima(pila1).caracter1,cima(pila1).caracter3);
sacar(punt_pila);
}
else{/*altura>1*/
switch(cima(pila1).num_hijos){
case 2:{/*las 2 llamadas correspondientes a este nodo estn hechas*/
sacar(punt_pila);
19

};break;
case 1:{
printf("\n Mover de %c a
%c\n",cima(pila1).caracter1,cima(pila1).caracter3);
registro_aux=cima(pila1);
sacar(punt_pila);
registro_aux.num_hijos=registro_aux.num_hijos+1;/*como voy a meter
algo en la pila, he llamado a otro hijo*/
meter(registro_aux,punt_pila);
/*las 4 ltimas lneas son solo para sumar 1 a num_hijos*/
meter(crear_registro(cima(pila1)),punt_pila);
};break;
case 0:{
registro_aux=cima(pila1);
sacar(punt_pila);
registro_aux.num_hijos=registro_aux.num_hijos+1;/*como voy a meter
algo en la pila, he llamado a otro hijo*/
meter(registro_aux,punt_pila);
/*las 4 ltimas lneas son solo para sumar 1 a num_hijos*/
meter(crear_registro(cima(pila1)),punt_pila);
};break;
}/*fin switch*/
} /*fin if*/
}/*fin while*/
printf("\n");
}/************FIN MAIN************/
elemento crear_registro(registro_anterior)
elemento registro_anterior;
{
elemento registro_creado;
registro_creado.altura=registro_anterior.altura-1;
registro_creado.num_hijos=0;/*como lo creo, an no tiene hijos*/
if(registro_anterior.num_hijos==1){/*esto quiere decir que aun no tiene
hijos y que el que vamos a crear es el primero*/
registro_creado.caracter1=registro_anterior.caracter1;
registro_creado.caracter2=registro_anterior.caracter3;
registro_creado.caracter3=registro_anterior.caracter2;
}
else{/*ya ha llamado a un hijo y vamos a crear el 2 y a meterlo en la pila*/
registro_creado.caracter1=registro_anterior.caracter2;
registro_creado.caracter2=registro_anterior.caracter1;
registro_creado.caracter3=registro_anterior.caracter3;
}
return registro_creado;
}/*FIN CREAR_REGISTRO*/

20

DEPURADOR DE ERRORES EN C:
/*PROGRAMA QUE ENCUENTRA ERRORES EN UN PROGRAMA EN C
USANDO PILAS*/
/*CON LISTAS ENLAZADAS*/
#include<stdio.h>
#include<stdlib.h>
typedef struct{ /*va a ser una pila de registros: cada en nodo.info*/
char alfanumerico;/*habr un registro de caracter y entero q indicar*/
int su_linea; /*el parentesis, corchete o llave y su linea en el fichero*/
} elemento;
elemento;
typedef struct NODE{
elemento info;
struct NODE *sgte;
};
typedef struct NODE nodo;
typedef nodo *pila;
/*****MAIN*****/
main(){
int vacia();
int sacar();
int meter();
elemento cima();
void trata_caracter();
pila pila1;
pila *punt_pila;
FILE *f;
char nombre_f[20];
char caracter;
int linea; /*indica en qu linea del fichero estamos*/
pila1=NULL;/*pila1 empieza siendo vacia*/
punt_pila=&pila1;
printf("\n Dame un fichero en c y te digo si tiene errores: ");
gets(nombre_f);
f=fopen(nombre_f,"r");
linea=1;
while((caracter=getc(f))!=EOF){
trata_caracter(caracter,linea,punt_pila);
if(caracter=='\n') linea=linea+1;}/*este bucle termina cuando se llega a EOF*/
fclose(f);
/*aqui se supone q ya se ha leido todo el fichero y dispongo d la pila*/
if(vacia(pila1)==1){ /*termino el fichero y la pila esta vacia*/
printf("\n Los parentesis, corchetes y llaves estan bien anidados:\n Tu programa
esta aparentemente bien hecho.\n");}
21

else{/*termino el fichero y la pila no esta vacia*/


printf("\n");
do{ /*el siguiente printf lo va a hacer siempre sobre una pila no vacia ===>
puedo usar CIMA*/
printf(" El caracter %c situado en la linea %d no esta bien
anidado.\n",cima(pila1).alfanumerico,cima(pila1).su_linea);
sacar(punt_pila); /*una vez muestro los resultados por pantalla voy vaciando la
pila*/
}while(vacia(pila1)==0);
printf(" Revisa tu programa.\n\n");
}
}/****FIN MAIN****/

void trata_caracter(caracter,linea,punt_pila)
char caracter;
int linea;
pila *punt_pila;
{
int vacia();
int meter();
int sacar();
elemento cima();
elemento registro;
registro.alfanumerico=caracter;
registro.su_linea=linea;
if(caracter=='(' || caracter=='[' || caracter=='{'){
meter(registro,punt_pila);
}
else{ /*el caracter no es de apertura*/
switch(caracter){
case ')': /* nos encontramos con ')'*/
if (vacia(*punt_pila)==1){ /*pila vacia*/
meter(registro,punt_pila);}
else{ /*pila no vacia*/
if((cima(*punt_pila)).alfanumerico=='('){
sacar(punt_pila);}
else{
meter(registro,punt_pila);}
};break;
case ']': /*nos encontramos con ']'*/
if (vacia(*punt_pila)==1){ /*pila vacia*/
meter(registro,punt_pila);}
else{ /*pila no vacia*/
if((cima(*punt_pila)).alfanumerico=='['){
sacar(punt_pila);}

22

else{
meter(registro,punt_pila);}
};break;
case '}': /*nos encontramos con '}'*/
if (vacia(*punt_pila)==1){ /*pila vacia*/
meter(registro,punt_pila);}
else{ /*pila no vacia*/
if((cima(*punt_pila)).alfanumerico=='{'){
sacar(punt_pila);}
else{
meter(registro,punt_pila);}
};break;
}
}
}/*FIN TRATA_CARACTER*/

23

CONVERSIN DE EXPRESIONES DE
NOTACIN INFIJA A POSFIJA EN C:
/*ESTE PROGRAMA ES UNA CALCULADORA BSICA.
SE INTRODUCEN NMEROS Y OPERADORES UNO POR UNO COMO EN UNA
CALCULADORA.
DESPUS SE PASA A NOTACIN POSFIJA Y SE GUARDA EN EN UN FICHERO.
SI SE QUIERE SE EVALA LA EXPRESIN Y SE DA UN RESULTADO
Las pilas tienen la implementacin de listas enlazadas*/
#include<stdio.h>
#include<stdlib.h>
typedef char elemento;
typedef struct NODE{
elemento info; /*pila de caracteres (pila de operadores y parentesis)*/
struct NODE *sgte;
};
typedef struct NODE nodo;
typedef nodo *pila;
main(){
void posfija();
float calcula();
char nombre_f[20];

printf(" Este programa transforma una expresion con notacion infija\n en su


correspondiente expresion con notacion posfija\n");
printf("\n Dame el nombre del fichero en el que guardar los datos: ");
gets(nombre_f);
posfija(nombre_f);
printf("\n Tu expresion en notacion posfija se ha almacenado en el fichero
%s\n\n",nombre_f);
}/************FIN MAIN************/
void posfija(nombre_f)/*POSFIJA*/
char nombre_f[20];
{
int vacia(),meter(),sacar(),tipo(),strlen(),tipo_dato,long_dato;
/*long_dato da la longitud de la cadena dato*/
elemento cima(),cima_aux;
pila pila1;
pila *punt_pila;
char dato[12];
FILE *f;
pila1=NULL;
24

punt_pila=&pila1;
f=fopen(nombre_f,"w");

do{
printf("\n Introduce el dato o el operador.\n Introduce '=' si quieres terminar la
expresion: ");
gets(dato);
tipo_dato=tipo(dato[0]);/*con esto identifico el dato que me han dado
y segun lo que valga lo tratar de una forma u otra*/
switch(tipo_dato){
case 1:{ /*es un real*/
long_dato=strlen(dato);
fprintf(f," %s",dato);
};break;
case 5:{ /*es un ')', luego la pila no est vacia y voy a sacar elementos*/
do{
fprintf(f," %c",cima(pila1));
sacar(punt_pila);
/*no hay riesgo d que este vacia pues debe haber un '(' al menos*/
if(vacia(pila1)==1){
cima_aux='(';}/*asi sale del bucle sin aplicar cima a un
apila vacia*/
else cima_aux=cima(pila1);
}while(cima_aux!='(');
/*finalizado este bucle, tenemos '(' en la cima de la pila. hay q sacarlo:*/
sacar(punt_pila);
};break;
case 6:{/*es un '=' =====> no hago nada*/
};break;
default:{/* +,-,*,/,( */
if(vacia(pila1)==1){/*pila vaca*/
meter(dato[0],punt_pila);}
else{
cima_aux=cima(pila1);/*no problemo xq pila1 no es vacia*/
while(vacia(pila1)!=1 && tipo(cima_aux)>=tipo(dato[0]) &&
tipo(cima(pila1))!=4){
fprintf(f," %c",cima(pila1));
sacar(punt_pila);
if(vacia(pila1)!=1) cima_aux=cima(pila1);
/*si pila1 esta vacia dejamos cima_aux igual xq no va
a entrar en el bucle de todas maneras*/
}

25

meter(dato[0],punt_pila);
}
}
}/*fin del switch*/
}while(dato[0]!='=');/*he terminado de pedir los datos.
ahora solo me queda sacar todo lo que queda en la pila:*/
while(vacia(pila1)!=1){/*ahora si no est vaca la vaco yo*/
fprintf(f," %c",cima(pila1));
sacar(punt_pila);
}
fclose(f);
}/*FIN POSFIJA*/
int tipo(caracter)/*esta funcin me devuelve un entero en funcion de*/
char caracter;/*lo que simbolice el caracter leido: real==>0, +- ==>1, etc.*/
{
if((int)caracter>=48 && (int)caracter<=57){/*si el codigo ascii del 1er
caracter corresp a un entero entonces s q va a ser un n entre 48 y 57*/
return 1;}
else{
if(caracter=='+' || caracter=='-'){
return 2;}
else{
if(caracter=='*' || caracter=='/'){
return 3;}
else{
if(caracter=='('){
return 4;}
else {
if(caracter==')'){
return 5;}
else {
if(caracter=='='){
return 6;}
else return 0;
}
/*tipo devuelve 0 si es un caracter no vlido*/
}
}
}
}
}/*FIN TIPO*/

26

EVALUADOR DE EXPRESIONES EN
NOTACIN POSFIJA EN C:
/*Las pilas tienen la implementacin de listas enlazadas
Hay que pasarle un fichero creado por el algoritmo anterior*/
#include<stdio.h>
#include<stdlib.h>
typedef double elemento;
typedef struct NODE{
elemento info; /*pila de reales*/
struct NODE *sgte;
};
typedef struct NODE nodo;
typedef nodo *pila;
main(){
char nombre_f[20];
double calcula();
printf("\n Necesito un fichero creado por el algoritmo POSFIJA.\n");
printf("\n Dame el nombre del fichero: ");
gets(nombre_f);
printf("\n El valor de la expresion que me has pasado es %f\n\n",calcula(nombre_f));
}/********FIN MAIN********/
/*la funcion calcula va cogiendo cadenas de caracteres delimitadas por espacios */
double calcula(nombre_f)/*CALCULA*/
char nombre_f[20];
{
int vacia(),sacar(),meter(),tipo();
double atof();/*atof transforma una cadena de caracteres en un real*/
elemento cima();
pila pila1,*punt_pila;
char caracter,dato[12];
double real_aux1,real_aux2;
FILE *f;
pila1=NULL;
punt_pila=&pila1;
f=fopen(nombre_f,"r");
while(caracter=getc(f)!=EOF){/*tras esta asignacion, caracter deberia valer ' '*/
fscanf(f,"%s",dato);
switch(tipo(dato[0])){
case 1:{/*tengo en dato una cadena q representa un real*/
meter(atof(dato),punt_pila);/*meto el real en la pila*/
};break;
27

default:{/*se trata de un operador*/


real_aux1=cima(pila1);
sacar(punt_pila);
real_aux2=cima(pila1);/*real_aux2 entro antes en la pila q real_aux1*/
sacar(punt_pila);
if(dato[0]=='+') meter(real_aux2+real_aux1,punt_pila);
else{
if(dato[0]=='-') meter(real_aux2-real_aux1,punt_pila);
else{
if(dato[0]=='*') meter(real_aux2*real_aux1,punt_pila);
else /*tenemos un '/'*/
meter(real_aux2/real_aux1,punt_pila);
}
}
}
}/*fin switch*/
}/*fin while*/
fclose(f);
return cima(pila1);
}/*FIN CALCULA*/
int tipo(caracter)/*esta funcin me devuelve un entero en funcion de*/
char caracter;/*lo que simbolice el caracter leido: real==>0, +- ==>1, etc.*/
{
if((int)caracter>=48 && (int)caracter<=57){/*si el codigo ascii del 1er
caracter corresp a un entero entonces s q va a ser un n entre 48 y 57*/
return 1;}
else{
if(caracter=='+' || caracter=='-'){
return 2;}
else{
if(caracter=='*' || caracter=='/'){
return 3;}
else{
if(caracter=='('){
return 4;}
else {
if(caracter==')'){
return 5;}
else {
if(caracter=='='){
return 6;}
else return 0;}
/*tipo devuelve 0 si es un caracter no vlido*/
}
}
}
}
}/*FIN TIPO*/

28

Bibliografa:
LIBROS:
Weiss.
Aho, Hopcroft, Ullman.
SITIOS:
http://www.cse.ucsc.edu/~elm/Classes/12b/w02/schedule.shtml
http://www.programacion.net
http://campusvirtual.uma.es/emetprog/LABORATORIO/matdocLP/teoria/d
oc/LP_curso_0304.Tema_7_Recursividad.pdf

29

Potrebbero piacerti anche