Está en la página 1de 6

Ejemplos de aplicacin del TAD pila

1. Evaluacin de expresiones postfijas


Una expresin aritmtica en notacin postfija (o notacin polaca inversa) es una secuencia formada por smbolos de dos tipos diferentes: operadores (para simplificar, consideraremos nicamente los operadores aritmticos binarios +, -, * y /) y operandos (para simplificar pensaremos en identificadores de una sola letra). Cada operador se escribe detrs de sus operandos. Por ejemplo, a la expresin siguiente, escrita en la notacin habitual (infija):
a*b/c

le corresponde la siguiente expresin en notacin postfija:


ab*c/

Si en la expresin infija aparecen parntesis, estos cambian la correspondiente expresin postfija slo si los parntesis alteran el orden de prioridad de los operadores: a/b+c*d-e*f, traducido a notacin postfija es: ab/cd*+ef*a/(b+c)*(d-e)*f, se traduce en cambio por: abc+/de-*f* Tres ventajas importantes de la notacin postfija frente a la convencional infija son las siguientes: En notacin postfija nunca son necesarios los parntesis. En notacin postfija no es necesario definir prioridades entre operadores. Una expresin postfija puede evaluarse de forma muy sencilla, como veremos enseguida. En el siguiente apartado de la leccin veremos un algoritmo para traducir expresiones de notacin infija a notacin postfija. Veamos ahora cmo evaluar una expresin escrita en notacin postfija. Una expresin en notacin postfija puede ser evaluada haciendo un recorrido de izquierda a derecha. Cuando se encuentra un operando, se apila en una pila de operandos. Cuando se encuentra un operador, se desapilan dos operandos de la pila, se realiza la correspondiente operacin y el resultado se apila en la pila de operandos. Este mtodo de evaluacin es mucho ms sencillo que el proceso necesario para evaluar una expresin escrita en notacin infija. A continuacin se presenta el algoritmo de evaluacin de expresiones en notacin postfija:
funcin evaluar(e:expresin) devuelve real { Devuelve el valor real de la expresin postfija e. } importa pilasDeSmbolos variables s,o1,o2,r:smbolo; p:pilaDeSmbolos; principio creaVaca(p); s:=siguienteSmbolo(e); mientrasQue sfinal hacer si esOperando(s) entonces apilar(p,s) sino o2:=cima(p); desapilar(p); o1:=cima(p); desapilar(p); r:=operar(o1,o2,s); apilar(p,r) fsi; s:=siguienteSmbolo(e) fmq; devuelve(cima(p)); desapilar(p) fin

Se ha supuesto lo siguiente: Se usa el mdulo pilasDeSmbolos, en el cual se ha definido el tipo smbolo, cuyos valores pueden ser operandos, operadores o el valor especial final; adems, existe la funcin esOperando

que devuelve verdad si y slo si el smbolo enviado como argumento es un operando; existe tambin la funcin operar, que a partir de dos operandos y un operador devuelve un nuevo operando que es el resultado de realizar la operacin. El TAD genrico pila se supone particularizado para datos de tipo smbolo en el mdulo pilasDeSmbolos, es decir, el parmetro formal elemento de la especificacin del TAD pila debe sustituirse por el tipo smbolo. Se supone predefinido el tipo expresin como una secuencia de smbolos. Adems, existe la funcin siguienteSmbolo que devuelve el siguiente smbolo de una expresin.

2. Traduccin de expresiones infijas a postfijas


Una vez resuelto el problema de evaluar una expresin escrita en notacin postfija, podemos plantearnos el de realizar la traduccin de expresiones infijas a postfijas para, as, tener resuelto el de evaluar expresiones infijas. Comparando una expresin infija con su correspondiente postfija, puede verse en primer lugar que los operandos mantienen el mismo orden en ambas notaciones. Por tanto, nicamente hay que mover operadores y quitar parntesis (si existen). Un primer algoritmo de traduccin es el siguiente: Aadir a la expresin un par de parntesis por cada operador. Esto significa aadir parntesis redundantes con las reglas de prioridad. Por ejemplo, de la expresin:
a/b+c*d-e*f

pasar a la expresin:
(((a/b)+(c*d))-(e*f))

Mover todos los operadores de forma que sustituyan a sus correspondientes parntesis derechos. En el ejemplo anterior:
(((ab/(cd*+(ef*-

Borrar todos los parntesis izquierdos. Es decir:


ab/cd*+ef*-

El problema del algoritmo anterior es que requiere dos recorridos de la expresin para traducirla: el primero para aadir todos los parntesis redundantes y el segundo para mover los operadores y eliminar parntesis. La solucin a ese problema se obtiene de la siguiente forma: puesto que el orden de los operandos es el mismo, cada vez que es leido un operando, se escribe en el resultado; cada vez que se lee un operador, hay que decidir si debe escribirse ya en el resultado o almacenarse en un dato auxiliar (veremos que ser una pila) hasta el momento de su escritura. Por ejemplo, para traducir la expresin a+b*c a su correspondiente postfija abc*+, hay que realizar los siguientes pasos: siguiente smbolo pila resultado comentario vaca inicializacin de la pila a vaca a el operando se escribe ya + + a el operador se apila porque no hay otro b + ab el operando se escribe ya * +* ab * tiene ms prioridad que +, luego se apila c +* abc el operando se escribe ya final vaca abc*+ se vuelca la pila sobre el resultado

Veamos ahora un ejemplo con parntesis: la expresin a*(b+c)/d. siguiente smbolo pila resultado comentario vaca inicializacin de la pila a vaca a el operando se escribe ya * * a el operador se apila porque no hay otro ( *( a el parntesis izquierdo se apila siempre b *( ab el operando se escribe ya + *(+ ab a un parntesis izquierdo slo lo saca el derecho c *(+ abc el operando se escribe ya ) * abc+ se desapila hasta el parntesis izquierdo, escribiendo el + que se ha desapilado / / abc+* / tiene igual prioridad que *, luego se saca * de la pila y se mete / d / abc+*d el operando se escribe ya final vaca abc+*d/ se vuelca la pila sobre el resultado En general, el problema se resuelve de la siguiente forma: a cada operador y a los parntesis se les asigna una prioridad en pila para cuando estn dentro de la pila y otra prioridad de llegada para cuando son leidos de la entrada; cada vez que se lee un operador o un parntesis izquierdo, si la pila es vaca, se apila, si no, se compara su prioridad de llegada con la prioridad en pila del smbolo que est en la cima de la pila; debe sacarse el operador de la cima de la pila cuando su prioridad en pila es mayor o igual que la prioridad de llegada del nuevo operador leido, y repetir el proceso con el nuevo operador que queda en la cima; cada vez que se lee un parntesis derecho, debe desapilarse el operador de la cima, escribirse en el resultado y desapilarse tambin el parntesis izquierdo que queda en la cima de la pila; las prioridades en pila y de llegada de los operadores +, -, * y /, y del parntesis izquierdo son: smbolo prioridad en pila prioridad de llegada *, / 2 2 +, 1 1 ( 0 3 El algoritmo que resuelve el problema de la traduccin infija a postfija es el siguiente:
algoritmo traducir(ent in:expresin; sal post:expresin) {Traduce la expresin infija in a su correspondiente postfija (post).} importa pilasDeSmbolos variables p:pilaDeSmbolos; s:smbolo; funcin prioridadDeLaPila(p:pila) devuelve 0..2 { Pre: p es una pila de smbolos s{(,+,-,*,/} } { Post: p=pilaVaca prioridadDeLaPila(p)=0; ppilaVaca cima(p)=( prioridadDeLaPila(p)=0; ppilaVaca cima(p) {+,-} prioridadDeLaPila(p)=1; ppilaVaca cima(p) {*,/} prioridadDeLaPila(p)=2 } funcin prioridadDeLlegada(s:smbolo) devuelve 1..3 { Pre: s{(,+,-,*,/} } { Post: s=( prioridadDeLlegada(s)=3; (s=+)(s=-) prioridadDeLlegada(s)=1; (s=*)(s=/) prioridadDeLlegada(s)=2 } principio creaVaca(p); iniciaExpresin(post); s:=siguienteSmbolo(in);

mientrasQue sfinal hacer si esOperando(s) entonces aadeSmbolo(post,s) sino si esParntesisDerecho(s) entonces mientrasQue not esParntesisIzquierdo(cima(p)) hacer aadeSmbolo(post,cima(p)); desapilar(p) fmq; desapilar(p) {quitar el parntesis izquierdo} sino mientrasQue prioridadDeLaPila(p)prioridadDeLlegada(s) hacer aadeSmbolo(post,cima(p)); desapilar(p) fmq; apilar(p,s) fsi fsi; s:=siguienteSmbolo(in) fmq; mientrasQue not esVaca(p) hacer aadeSmbolo(post,cima(p)); desapilar(p) fmq; aadeSmbolo(post,final) fin

Se ha supuesto lo siguiente: Adems de la funcin esOperando, existen las funciones booleanas esParntesisDerecho y esParntesisIzquierdo. Existen los algoritmos iniciaExpresin y aadeSmbolo que crean la expresin vaca y aaden un nuevo smbolo a la derecha de una expresin, respectivamente.

3. Recorrido de un laberinto
En este apartado va a utilizarse una pila como dato auxiliar para resolver el problema de encontrar la salida de un laberinto. Existe una entrada al laberinto y, una vez dentro de l, el paseante se encuentra con paredes que le impiden el paso en muchas direcciones. Debe elegirse un camino, en caso de que no lleve a la salida hay que volver atrs y continuar en una direccin diferente, y as hasta encontrar la nica salida existente. El siguiente es un ejemplo de laberinto:

En primer lugar, para representar el laberinto podemos utilizar una estructura de datos consistente en una matriz de mp componentes booleanas de forma que un valor falso en una componente indica que en la correspondiente posicin del laberinto hay una pared, mientras que el valor verdad representa la existencia de un espacio libre. Supongamos que la entrada se realiza siempre por la componente 1,1 (como en la figura) y la salida por la componente m,p. La situacin del paseante en el laberinto estar siempre descrita por la fila i y la columna j de su posicin en la matriz. Como puede verse, desde cada posicin alcanzada en el interior del laberinto puede optarse por continuar en ocho direcciones diferentes (Norte, NorEste, Este, SurEste, Sur, SurOeste, Oeste y NorOeste):

NO
[i-1,j-1]

N
[i-1,j]

NE
[i-1,j+1]

O
[i,j] [i,j-1]

E
[i,j+1]

SO
[i+1,j-1]

S
[i+1,j]

SE
[i+1,j+1]

No todas las posiciones i,j permiten moverse en ocho direcciones diferentes (si i=1 m j=1 p, entonces son menos los movimientos posibles). Para evitar ese problema, orlaremos la matriz que representa el laberinto con una pared (componentes con valor falso) en las filas 0 y m+1 y en las columnas 0 y p+1. La solucin al problema es la siguiente: al llegar a una nueva posicin se examinan todas las posibles direcciones, desde la Este a la Noreste (en el sentido de las agujas de un reloj); cada vez que se realiza un movimiento, se guarda ste en una pila (posicin y direccin del movimiento); si se llega a una posicin desde la que no se puede seguir, hay que volver atrs, desapilando el ltimo movimiento y realizando el siguiente posible. Para evitar pasar dos veces por el mismo camino se necesita almacenar en otra matriz de booleanos auxiliar (inicializada con valores falso) para marcar las posiciones por las que ya se ha pasado (con valor verdad).
constantes m = ...; p = ... tipo laberinto = vector[0..m+1,0..p+1] de booleano; direccin = (E,SE,S,SO,O,NO,N,NE); movimiento = registro fil:1..m; col:1..p; dir:direccin freg algoritmo inviertePila(ent p:pilaDeMov; sal pI:pilaDeMov) principio creaVaca(pI); mientrasQue not esVaca(p) hacer apilar(pI,cima(p)); desapilar(p) fmq fin algoritmo camino(ent lab:laberinto) { Escribe en pantalla, si existe, un camino del laberinto que va de la posicin 1,1 a la posicin m,p. } variables hePasado:vector[1..m,1..p] de booleano; mov:movimiento; pila,pilaInv:pilaDeMov; xito:booleano; principio {inicializacin de la matriz de marcas a falso} para i:=1 hasta m hacer para j:=1 hasta p hacer hePasado[i,j]:=falso fpara fpara; {se parte de la casilla 1,1 hacia el Este} xito:=falso; hePasado[1,1]:=verdad; mov.fil:=1; mov.col:=1; mov.dir:=E; creaVaca(pila); apilar(pila,mov); mientrasQue not esVaca(pila) and not xito hacer {ver la posicin actual y la direccin del movimiento} mov:=cima(pila); seleccin {clculo de la nueva posicin} mov.dir=N: nuevaFil:=mov.fil-1; nuevaCol:=mov.col; mov.dir=NE: nuevaFil:=mov.fil-1; nuevaCol:=mov.col+1;

mov.dir=E: nuevaFil:=mov.fil; nuevaCol:=mov.col+1; mov.dir=SE: nuevaFil:=mov.fil+1; nuevaCol:=mov.col+1; mov.dir=S: nuevaFil:=mov.fil+1; nuevaCol:=mov.col; mov.dir=SO: nuevaFil:=mov.fil+1; nuevaCol:=mov.col-1; mov.dir=O: nuevaFil:=mov.fil; nuevaCol:=mov.col-1; mov.dir=NO: nuevaFil:=mov.fil-1; nuevaCol:=mov.col-1 fseleccin; si (nuevaFil=m) and (nuevaCol=p) entonces {se llega a la salida} mov.fil:=m; mov.col:=p; mov.dir:=E; apilar(mov); xito:=verdad sino si lab[nuevaFil,nuevaCol] and not hePasado[nuevaFil,nuevaCol] entonces {nueva posicin} hePasado[nuevaFil,nuevaCol]:=verdad; mov.fil:=nuevaFil; mov.col:=nuevaCol; mov.dir:=E; apilar(pila,mov) sino {vuelta atrs} desapilar(pila); mientrasQue (mov.dir=NE) and not esVaca(pila) hacer mov:=cima(pila); desapilar(mov) fmq; si mov.dir<NE entonces mov.dir:=sucesor(mov.dir); apilar(p.mov) fsi fsi fsi fmq; si xito entonces inviertePila(pila,pilaInv); mientrasQue not esVaca(pilaInv) hacer mov:=cima(pilaInv); desapilar(pilaInv); escribirLnea('Ir de ',mov.fil,',',mov.col,' hacia el ',mov.dir) fmq sino escribirLnea('No hay salida!') fsi fin

También podría gustarte