21 Capítulo 2. LA PILA (STACK). 2.1 Definición y ejemplos. Una pila es un conjunto ordenado de elementos en el cual se pueden agregar y eliminar elementos de un extremo, el cual es llamado el tope de la pila. La pila es un objeto dinámico en constante cambio. La definición de pila especifica que un solo extremo de la pila se designa como tope.
22 Pueden colocarse nuevos elementos en el tope de la pila o se pueden quitar elementos de él. La característica más importante de la pila es que el último elemento insertado en ella es el primero en suprimirse. Por esta razón, una pila se denomina como una estructura LIFO (Last In First Out) en la cual, el último elemento insertado, será el primero en ser eliminado.
23 Tabla 1. Crecimiento y decrecimiento de una Pila. G I F F F H H E E E E E E E D D D D D D D D C C C C C C C C B B B B B B B B A A A A A A A A
24 2.2 Funciones primitivas. Las funciones básicas definidas sobre una pila son push y pop. pila. La función push inserta un nuevo elemento en el tope de la pila. La función pop elimina el elemento indicado por el tope de la Existen otras funciones útiles al usar pilas, por ejemplo, antes de aplicar la operación pop a una pila, se debe verificar que la pila no esté vacía. Así, la función isempty determina si una pila está o no vacía.
25 Otra operación que puede ejecutarse sobre una pila es determinar cuál es el elemento que se encuentra en el tope de la pila pero sin eliminarlo. Esta función puede llamarse stacktop. 2.3 Representación de pilas en C. Hay varias formas de representar una pila en C y cada una de ellas es sólo una implementación del concepto introducido en la sección anterior. Aunque un arreglo no es una pila, bien puede ser usado para representar una. (Ejemplo del arreglo implementando una pila).
26 Una pila es fundamentalmente un objeto dinámico cuyo tamaño se modifica en forma continua conforme se agregan y remueven elementos. (Ejemplo de una pila dinámica). Un programador siempre debe preocuparse por la legibilidad del código que produce. 2.4 Ejemplos clásicos del uso de pilas. Esta sección revisa dos ejemplos clásicos del uso de pilas, no son las únicas aplicaciones que se tienen de este tipo de estructura de datos, pero sí son de los más representativos.
27 2.4.1 Análisis básico de expresiones. Considérese la siguiente expresión matemática: + + 2 5 4 3 7 y j y x x Cuya representación lineal es: 7 ((x * ((x + y) / (j - 3)) + y) / (4 5/2)). Cómo saber si la expresión está correctamente balanceada en cuanto a paréntesis se refiere?
28 Considérese ahora la siguiente expresión matemática: { x + ( y [ a + b] ) c [( d + e) ]} ( h ( j ( k [ l n] ))) Cuya representación lineal es: {x + (y [a + b]) * c [(d + e)]} / (h (j (k [l - n]))). Cómo saber si la expresión está correctamente balanceada en cuanto a símbolos de agrupación se refiere? Cómo saber que un símbolo de agrupación está cerrando a su correspondiente símbolo de apertura? Considere el siguiente algoritmo:
29 valid = true; s = the empty stack; while(not end of string){ read the next symbol of the string; if(symbol == ( symbol == [ symbol == { ) push(s, symbol); else if(symbol == ) symbol == ] symbol == } ){ if(isempty(s)) valid = false; else{ i = pop(s); if(i is not equivalent to symbol) valid = false; } }
30 } /* while s */ if(!isemtpy(s)) valid = false; if(valid) printf( The string is valid\n ); else printf( The string is invalid\n ); 2.4.2 Notación interfija, postfija y prefija. Considere la suma de dos números A y B. Aplicar el operador + a los operandos A y B, y escribir la suma como A + B tiene el nombre de representación interfija.
31 Hay otras dos notaciones alternas para expresar la suma de A y B usando los mismos símbolos A, B y +: + A B representación prefija. A B + representación postfija. Los prefijos pre, pos e inter hacen referencia a la posición relativa del operador en relación a los operandos. Una función en C para retornar la suma de dos argumentos invocada mediante add(s, b) utiliza notación prefija, ya que el operador add precede a los operandos. Considere la siguiente expresión:
32 A + B * C indica implícitamente A + (B * C). Suponga que se desea convertir la expresión anterior a su representación en postfija. Entonces, aplicando las reglas de precedencia, primero se convierte la parte de la expresión que se evalúa primero: A + (B * C) forma interfija. A + (BC *) se convierte la multiplicación. A (BC *) + convierte la suma. A B C * + representación postfija.
33 Las únicas reglas que deben recordarse durante el proceso de conversión son las siguientes: 1.Las operaciones con mayor precedencia se convierten primero. 2.Después de que una parte de la expresión se ha convertido a postfija, se considerará como un operando único. Ejemplo: 1.(A + B) * C forma interfija. 2.(A B +) * C se convierte la adición. 3.(A B +) C * convierte la multiplicación.
34 4.A B + C * representación postfija. Ejercicio: Convertir las siguientes expresiones en su representación postfija: 1. A+B 2. A+B-C 3. (A+B) * (C-D) 4. A$B*C D+E/F/(G+H) 5. ((A+B)*C (D-E))$(F+G) 6. A B/(C*D$E)
35 El signo de $ en las expresiones anteriores, representa el símbolo de exponenciación y es el de más alta precedencia. Las reglas para convertir una expresión de interfija a prefija son idénticas. El único cambio es que el operador se coloca antes de los operandos en lugar de después de ellos. Ejercicio: Convierta las expresiones anteriores a su representación prefija. En base a los ejercicios anteriores, debe observarse que la representación prefija no siempre es una imagen reflejo de la representación postfija.
36 El orden de los operadores en las expresiones postfijas determina el orden real de las operaciones al evaluar la expresión, haciendo innecesario el uso de paréntesis. Ejercicio: Crear un algoritmo, así como su implementación, para convertir una expresión interfija en: 1.Postfija. 2.Prefija. Con valores concretos en las expresiones postfijas. Cómo evaluar una expresión postfija? Considere el siguiente algoritmo:
37 Algoritmo para evaluar una expresión postfija: opndstack = the empty satck; while(not end of input){ symbol = next input character; if(symbol is an operand) push(opndstack, symbol); else{ opnd2 = pop(opndstack); opnd1 = pop(opndstack); value = opnd1 symbol opnd2; push(opndstack, value); } } return pop(opndstack);
38 Solución a los ejercicios de conversión: Prefija: Postfija: 1. +AB AB+ 2. -+ABC AB+C- 3. *+AB-CD AB+CD-* 4. +-*$ABCD//EF+GH AB$C*D-EF/GH+/+ 5. $-*+ABC-DE+FG AB+C*DE--FG+$ 6. -A/B*C$DE ABCDE$*/-