Está en la página 1de 11

Estructura PILA

Expresiones en notaciones Infija,


prefija y Postfija

Msc. Lesbia Valerio Lacayo

1
Msc. Lesbia Valerio Lacayo
La PILA y sus Utilidades

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.

Expresión de evaluación y análisis sintáctico

Se calcula empleando la notación polaca inversa utilizando una estructura de pila para los posibles valores. Las
expresiones pueden ser representadas en prefijo, infijo, postfijo.

La conversión de una forma de la expresión a otra forma necesita de una pila. Muchos compiladores utilizan una pila
para analizar la sintaxis de las expresiones, bloques de programa, etc. Antes de traducir el código de bajo nivel.

La mayoría de los lenguajes de programación son de contexto libre de los idiomas que les permite ser analizados con
máquinas basadas en la pila.

Por ejemplo, el cálculo: ((1 + 2) * 4) + 3, puede ser anotado como en notación postfija con la ventaja de no prevalecer
las normas y los paréntesis necesario:

12+4*3+

La expresión es evaluada de izquierda a derecha utilizando una pila:

 Apilar cuando se enfrentan a un operando y


 Desafilar dos operandos y evaluar el valor cuando se enfrentan a una operación.
 Apilar el resultado.

De la siguiente manera (la Pila se muestra después de que la operación se haya llevado a cabo):

ENTRADA OPERACION PILA

1 Apilar operando 1
2 Apilar operando 1, 2
+ Añadir 3
4 Apilar operando 3, 4
* Multiplicar 12
3 Apilar operando 12, 3
+ Añadir 15

2
Msc. Lesbia Valerio Lacayo
Expresiones en notaciones infija, prefija y sufija
Cuando usted escribe una expresión aritmética como B * C, la forma de la expresión le proporciona información para que
pueda interpretarla correctamente. En este caso sabemos que la variable B está siendo multiplicada por la variable C, ya
que el operador de multiplicación * aparece entre ellos en la expresión. Este tipo de notación se conoce como infija ya
que el operador está entre los dos operandos sobre los que está actuando.

Considere otro ejemplo de notación infija, A + B * C. Los operadores + y * siguen apareciendo entre los operandos, pero
hay un problema. ¿Sobre qué operandos actúan? ¿Opera el + sobre A y B o el * opera sobre B y C? La expresión parece
ambigua.

De hecho, usted ha estado leyendo y escribiendo estos tipos de expresiones durante mucho tiempo y no le causan ningún
problema. La razón de esto es que usted sabe algo sobre los operadores + y *. Cada operador tiene un nivel de precedencia.

Los operadores de mayor precedencia se utilizan antes que los operadores de menor precedencia. Lo único que puede
cambiar ese orden es la presencia de paréntesis. El orden de precedencia para los operadores aritméticos ubica la
multiplicación y la división por encima de la suma y la resta. Si aparecen dos operadores de igual precedencia, se utiliza
un ordenamiento o asociatividad de izquierda a derecha.

Interpretemos la expresión problemática A + B * C usando la precedencia de los operadores. B y C se multiplican primero


y A se añade a ese resultado. (A + B) * C forzaría la suma de A y B antes de la multiplicación. En la expresión A + B + C,
por precedencia (vía asociatividad), el + que está más a la izquierda operaría primero.

Aunque todo esto puede ser obvio para usted, recuerde que las computadoras necesitan saber exactamente qué
operadores deben ejecutarse y en qué orden. Una forma de escribir una expresión que garantice que no habrá confusión
con respecto al orden de las operaciones es crear lo que se denomina expresión completamente agrupada.

Este tipo de expresión utiliza una pareja de paréntesis para cada operador. Los paréntesis dictan el orden de las
operaciones; no hay ambigüedad. Tampoco es necesario recordar las reglas de precedencia.

La expresión A + B * C + D se puede reescribir como ((A + (B * C)) + D) para mostrar que la multiplicación ocurre primero,
seguida por la adición que está más a la izquierda. A + B + C + D se puede escribir como ((A + B) + C) + D) ya que las
operaciones de adición se asocian de izquierda a derecha.

Hay otros dos formatos de expresión muy importantes que, al principio, pueden no parecer obvios. Considere la expresión
infija A + B. ¿Qué pasaría si moviéramos el operador antes de los dos operandos? La expresión resultante sería + A B.
Del mismo modo, podríamos mover el operador al final. Obtendríamos A B +. Estas expresiones se ven un poco extrañas.

Estos cambios en la posición del operador con respecto a los operandos crean dos nuevos formatos de expresión,
la notación prefija y la notación sufija (o postfija). La notación prefija requiere que todos los operadores precedan a
los dos operandos sobre los que actúan. La notación sufija, por otro lado, requiere que sus operadores aparezcan después
de los operandos correspondientes.

Expresión infija Expresión prefija Expresión sufija

A+B +AB AB+

A+B*C +A*BC ABC*+

3
Msc. Lesbia Valerio Lacayo
A + B * C se escribiría como + A * B C en la notación prefija. El operador de multiplicación aparece inmediatamente antes
de los operandos B y C, denotando que el * tiene precedencia sobre el +. El operador de adición aparece entonces antes
de la A y del resultado de la multiplicación.

En notación sufija, la expresión sería A B C * +. Una vez más, el orden de las operaciones se conserva ya que el * aparece
inmediatamente después de la B y la C, denotando que el * tiene precedencia, con el + apareciendo después. Aunque los
operadores se movieron y ahora aparecen antes o después de sus respectivos operandos, el orden de cada operando se
mantuvo exactamente igual en relación con los demás.

Ahora considere la expresión infija (A + B) * C. Recuerde que en este caso, la notación infija requiere los paréntesis para
forzar que se lleve a cabo la adición antes de la multiplicación.

Sin embargo, cuando A + B fue escrito en notación prefija, el operador de adición fue movido simplemente antes de los
operandos, + A B. El resultado de esta operación se convierte en el primer operando para la multiplicación. El operador
de multiplicación se mueve delante de toda la expresión, dándonos * + A B C. Igualmente, en notación sufija A B + obliga
a que la adición ocurra primero. La multiplicación se puede hacer sobre ese resultado y el operando restante C. La
expresión sufija correcta es entonces A B + C *.

Considere nuevamente estas tres expresiones (ver la Tabla). Ha ocurrido algo muy importante. ¿A dónde se fueron los
paréntesis? ¿Por qué no los necesitamos en las notaciones prefija y sufija? La respuesta es que los operadores ya no son
ambiguos con respecto a los operandos sobre los que actúan. Solamente la notación infija requiere los símbolos adicionales.
El orden de las operaciones dentro de las expresiones prefijas y sufijas está completamente determinado por la posición
del operador y nada más. De muchas maneras, esto hace que la notación infija sea la notación menos deseable de usar.

Expresión infija Expresión prefija Expresión sufija

(A + B) * C *+ABC AB+C*

La siguiente Tabla muestra algunos ejemplos adicionales de expresiones infijas y las expresiones equivalentes en
notaciones prefija y sufija. Asegúrese de entender cómo son equivalentes en términos del orden de las operaciones que
se están realizando.

Expresión infija Expresión prefija Expresión sufija

A+B*C+D ++A*BCD ABC*+D+

(A + B) * (C + D) *+AB+CD AB+CD+*

A*B+C*D +*AB*CD AB*CD*+

A+B+C+D +++ABCD AB+C+D+

4
Msc. Lesbia Valerio Lacayo
Conversión de expresiones infijas a notaciones prefija y sufija

Hasta el momento, hemos utilizado métodos ad hoc para convertir entre expresiones infijas y las expresiones
equivalentes en notaciones prefija y sufija. Como es de esperar, hay formas algorítmicas para realizar la conversión
que permiten transformar correctamente cualquier expresión de cualquier complejidad.

La primera técnica que vamos a considerar utiliza la noción de una expresión completamente agrupada que se discutió
anteriormente. Recordemos que A + B * C se puede escribir como (A + (B * C)) para mostrar explícitamente que la
multiplicación tiene precedencia sobre la adición. Sin embargo, al observar más de cerca, puede verse que cada pareja
de paréntesis también indica el comienzo y el final de un par de operandos con el operador correspondiente en la mitad.

Observe el paréntesis derecho en la subexpresión (B * C) anterior. Si tuviéramos que mover el símbolo de multiplicación
a esa posición y quitar el paréntesis izquierdo correspondiente, nos daría B C *, de hecho, habríamos convertido la
subexpresión a notación sufija. Si el operador de adición también es movido a la posición de su paréntesis derecho
correspondiente y se elimina el paréntesis izquierdo que le corresponde, se produciría la expresión sufija completa.

Traslado de operadores a la derecha para producir la notación sufija

Si hacemos lo mismo, pero en lugar de mover el símbolo a la posición del paréntesis derecho, lo movemos a la izquierda,
obtenemos la notación prefija. La posición de la pareja de paréntesis es en realidad una pista sobre la posición final
del operador encerrado entre ellos.

Traslado de operadores a la izquierda para producir la notación prefija

Así que, para convertir una expresión, independientemente de su complejidad, ya sea a notación prefija o a notación
sufija, agrúpela completamente utilizando el orden de las operaciones. A continuación, mueva cada operador a la posición
correspondiente de los paréntesis izquierdo o derecho dependiendo de si desea obtener la expresión en notación prefija
o en notación sufija.

La siguiente es una expresión más compleja: (A + B) * C - (D - E) * (F + G). A continuación la conversión a las notaciones
sufija y prefija.

5
Msc. Lesbia Valerio Lacayo
Conversión general de notación infija a notación sufija

Necesitamos desarrollar un algoritmo para convertir cualquier expresión infija a una expresión sufija. Para hacer esto
vamos a examinar más de cerca el proceso de conversión.

Consideremos una vez más la expresión A + B * C. Como se muestra arriba, A B C * + es la equivalencia en notación sufija.
Ya hemos observado que los operandos A, B y C permanecen en sus posiciones relativas. Sólo los operadores cambian de
posición. Veamos de nuevo los operadores en la expresión infija. El primer operador que aparece de izquierda a derecha
es el +. Sin embargo, en la expresión sufija, el + está al final dado que el siguiente operador, *, tiene precedencia sobre
la adición. El orden de los operadores en la expresión original se invierte en la expresión sufija resultante.

A medida que procesamos la expresión, los operadores tienen que ser guardados en alguna parte, ya que sus operandos
derechos correspondientes no aparecen todavía. También, el orden de estos operadores guardados puede necesitar ser
invertido debido a su precedencia. Ése es el caso con la adición y la multiplicación en este ejemplo. Dado que el operador
de adición aparece antes del operador de multiplicación y tiene menor precedencia, necesita aparecer después de que se
use el operador de multiplicación. Debido a esta inversión del orden, tiene sentido considerar el uso de una pila para
almacenar a los operadores hasta que se necesiten.

Y ¿qué ocurrirá con (A + B) * C? Recuerde que A B + C * es la equivalencia en notación sufija. De nuevo, procesando esta
expresión infija de izquierda a derecha, vemos primero el +. En este caso, cuando vemos el *, el + ya se ha transcrito en
la expresión de resultado porque tiene precedencia sobre el * en virtud de los paréntesis. Ahora podemos empezar a ver
cómo funcionará el algoritmo de conversión. Cuando veamos un paréntesis izquierdo, lo guardaremos para indicar que habrá
otro operador de alta precedencia. Ese operador tendrá que esperar hasta que aparezca el paréntesis derecho
correspondiente para indicar su posición (recuerde la técnica de agrupar completamente). Cuando aparezca ese paréntesis
derecho, el operador puede ser extraído de la pila.

Al recorrer la expresión infija de izquierda a derecha, usaremos una pila para almacenar los operadores. Esto
proporcionará la inversión que hemos observado en el primer ejemplo. El tope de la pila siempre será el operador guardado
más recientemente. Siempre que leamos a un operador nuevo, tendremos que comparar la precedencia de ese operador
con la de los operadores que ya estén en la pila, si los hay.

Suponga que la expresión infija es una cadena de símbolos delimitados por espacios. Los símbolos de operaciones son *, /,
+ y -, junto con los paréntesis izquierdo y derecho, ( y ). Los símbolos de operandos son los identificadores de un solo
carácter A, B, C, y así sucesivamente. Los siguientes pasos producirán una cadena de símbolos en el orden sufijo.

1. Crear una pila vacía llamada pilaOperadores para almacenar los operadores. Crear una lista vacía para almacenar
la salida.
2. Convertir la cadena de entrada de notación infija a una lista, usando el método split.
3. Recorrer la lista de símbolos de izquierda a derecha:
o Si el símbolo es un operando, agregarlo al final de la lista de salida.
o Si el símbolo es un paréntesis izquierdo, enviarlo a pilaOperadores.
o Si el símbolo es un paréntesis derecho, extraer de pilaOperadores hasta que el correspondiente paréntesis
izquierdo se haya extraído. Agregar cada operador al final de la lista de salida.
o Si el símbolo es un operador *, /, +, ó -, incluirlo en pilaOperadores. No obstante, extraer previamente de la pila
los operadores que tengan mayor o igual precedencia y agregarlos a la lista de salida.
4. Cuando la expresión de entrada ha sido procesada completamente, verificar pilaOperadores. Todos los
operadores que aún estén almacenados en ella se deben enviar a la lista de salida.

6
Msc. Lesbia Valerio Lacayo
La Figura muestra el algoritmo de conversión trabajando sobre la expresión A * B + C * D. Observe que el primer operador
* se elimina al verse el operador +. Además, el + permanece en la pila cuando aparece el segundo *, ya que la multiplicación
tiene precedencia sobre la adición. Al final de la expresión infija, se extrae dos veces de la pila, eliminando ambos
operadores y colocando el + como el último operador en la expresión sufija.

Conversión de A * B + C * D a notación sufija

7
Msc. Lesbia Valerio Lacayo
Evaluación de expresiones en notación sufija

Como ejemplo final sobre las pilas, consideraremos la evaluación de una expresión que ya está en notación sufija. En este
caso, una pila será de nuevo la estructura de datos elegida. Sin embargo, al recorrer la expresión sufija, son los operandos
los que deben esperar, no los operadores como en el algoritmo de conversión anterior. Otra forma de pensar en la solución
es que siempre que se vea un operador en la entrada, se usarán en la evaluación los dos operandos más recientes.

Para ver esto con más detalle, considere la expresión sufija 4 5 6 * +. Al recorrer la expresión de izquierda a derecha,
usted encuentra primero los operandos 4 y 5. En este punto, usted todavía no está seguro respecto a qué hacer con ellos
hasta que vea el siguiente símbolo. Ubicando cada uno en la pila asegura que estén disponibles si un operador viene a
continuación.

En este caso, el símbolo siguiente es otro operando. Así pues, como antes, inclúyalo en la pila y examine el símbolo siguiente.
Ahora vemos un operador, *. Esto significa que los dos operandos más recientes necesitan ser utilizados en una operación
de multiplicación. Al extraer dos veces de la pila, podemos obtener los operandos adecuados y luego realizar la
multiplicación (en este caso obtenemos 30 como resultado).

Ahora podemos manejar este resultado colocándolo de nuevo en la pila para que pueda ser utilizado como un operando para
los operadores posteriores en la expresión. Cuando se procesa el operador final, sólo quedará un valor en la pila.

Se extrae y se devuelve como el resultado de la expresión. La Figura muestra el contenido de la pila a medida que se
procesa toda la expresión de ejemplo.

Contenido de la pila durante la evaluación

La siguiente figura muestra un ejemplo un poco más complejo, 7 8 + 3 2 + /. Hay dos cosas a tener en cuenta en este
ejemplo. En primer lugar, el tamaño de la pila crece, disminuye y, a continuación, crece de nuevo a medida que las
subexpresiones se evalúan. En segundo lugar, la operación de división necesita ser manejada cuidadosamente. Recuerde
que los operandos en la expresión sufija están en su orden original ya que la notación sufija cambia sólo la ubicación de los
operadores.

Cuando los operandos para la división se extraen de la pila, estos se invierten. Dado que la división no es un operador
conmutativo, en otras palabras 15/515/5 no es lo mismo que 5/155/15, debemos estar seguros de que el orden de los
operandos no esté intercambiado.

8
Msc. Lesbia Valerio Lacayo
Un ejemplo más complejo de evaluación

Supongamos que la expresión sufija es una cadena de símbolos delimitados por espacios. Los operadores son *, /, + y -;
además, se supone que los operandos son valores enteros de un solo dígito. La salida será un resultado entero.

1. Crear una pila vacía llamada pilaOperandos.


2. Convertir la cadena a una lista mediante la aplicación del método split.
3. Recorrer la lista de símbolos de izquierda a derecha.
o Si el símbolo es un operando, convertirlo de tipo cadena a tipo entero e incluir el valor en pilaOperandos.
o Si el símbolo es un operador, *, /, +, ó -, éste necesitará dos operandos. Extraer dos veces de pilaOperandos. La
primera extracción corresponde al segundo operando y la segunda al primer operando. Realizar la operación
aritmética. Incluir el resultado en pilaOperandos.
4. Cuando la expresión de entrada se ha procesado completamente, el resultado queda en la pila. Extraerlo de
pilaOperandos y devolver dicho valor.

A continuación, algunas propuestas de algoritmos para evaluar y realizar conversiones de una expresión a sus
respectivas notaciones infija, prefija y postfija.

9
Msc. Lesbia Valerio Lacayo
Algoritmo de Evaluación de una expresión POSTFIJA

Opndstk = la pila vacia;

/* explora la cadena de ingresos leyendo*/


/* un elemento a la vez hacia symb */

while (no sea el fin de la entrada) {


symb = siguiente carácter de entrada
if (symb es un operando)
push (opndstk, symb);
else {
/* symb es un operador */
opnd2= pop (opndstk);
opnd1= pop (opndstk);
value= resultado de aplicar symb a opnd1 y opnd2;
push (opndstk, value); }
}}
return (pop(opndstk));

La conversión de cada una de las notaciones es sencilla, sin embargo hay que tomar en cuenta algunos aspectos,
entre ellos, el orden de precedencia y los limitadores (paréntesis, llaves o corchetes).

Tenemos tres tipos de limitadores (), {}, [].

El siguiente algoritmo revisa el caso de los tres tipos de limitadores:

valid = true
while (mientras no se haya leído toda la cadena)
leer el siguiente símbolo de la cadena
si símbolo == ‘ ( ’ || símbolo == ‘ [ ’ || símbolo == ‘ { ’
push(PILA,simbolo);
si símbolo == ‘ ) ’ || símbolo == ‘ ] ’ || símbolo == ‘ } ’
si empty(PILA)
valid = false
else
i = pop( PILA )
si ( i no es equivalente del símbolo que abre )
valid = false
fin del while
si la pila no está vacía // No se verificaron todos los símbolos
valid = false, e imprimir cadena no válida
si valid = true
imprimir cadena válida
en caso contrario
imprimir cadena no válida

El siguiente algoritmo evalúa de Notación Infija a Notación Postfija.

función_evalua_posfija{ 10
Msc.= Lesbia
tope -1; Valerio Lacayo
while (no sea el fin de la cadena){
El siguiente algoritmo evalúa de Notación Infija a Notación Postfija.

función_evalua_posfija{
tope = -1;
while (no sea el fin de la cadena){
simbolo = carácter de la cadena.
ifsimbolo es un operando
push(tope,simbolo);
else{ /* simbolo es un operador */
opnd2 = pop(tope);
opnd1 = pop(tope)
resultado=/*aplicar a simbolo opnd1 y opnd2*/
push(tope, resultado)
}
fin else
fin while
return(pop(tope));
}

El algoritmo de evaluación es muy fácil, ahora presento el algoritmo de Conversión Infija-Postfija.

TOPE = NULL;
while (no sea el fin de la cadena){
simbolo = carácter izquierdo de la cadena entrada;
if (simbolo es un operando)
cadenaposfija = cadenaposfija + símbolo;
else{
while (!empty(TOPE) &&prcd(pop(TOPE),símbolo)){
topsimbolo = pop(TOPE)
cadenaposfija = cadenaposfija + topsimbolo;
}//fin del while de precedencia
if (empty() || simbolo != ‘)’) push(simbolo);
else{
while ( (topsimbolo = pop(TOPE)) !=‘(’ ){
cadenaposfija = cadenaposfija+ topsimbolo;
}//fin del else
}//fin del else si no es operando
}//fin del while de la cadena
while (!empty(TOPE)){//extraer operadores restantes
topsimbolo = pop(TOPE)
cadenaposfija = cadenaposfija + topsimbolo;
}fin del while para extraer operadores

El algoritmo necesita de algunas consideraciones:

- Uso de paréntesis.
- Prioridad de operadores.
- El operador que aparece primero en la cadena es el que se aplica primero.

11
Msc. Lesbia Valerio Lacayo

También podría gustarte