Ver Mensaje Individual
  #1 (permalink)  
Antiguo 25/08/2011, 17:00
Avatar de razpeitia
razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 19 años, 1 mes
Puntos: 1360
[Aporte] Evaluar expresiones aritmeticas

Siempre trato de evitar el uso de la función eval pero hay situaciones en que su uso es simplemente tentador.

Uno de estos casos es al momento de evaluar expresiones aritméticas. Tener una cadena de este modo:
Código:
"2 * 2 + 3"
Parece irresistible pasarlo por la función eval para que nos regrese su valor numérico.

En vista de esto, me puse a estudiar e implementar uno de los muchos algoritmos de Dijkstra llamado Shunting-yard para pasar de expresiones infijas a expresiones prefijas.

Aquí dejo el código.
Código Python:
Ver original
  1. from collections import deque
  2.  
  3. class Stack:
  4.     def __init__(self):
  5.         self.__stack = []
  6.        
  7.     def top(self):
  8.         return self.__stack[-1]
  9.    
  10.     def pop(self):
  11.         self.__stack.pop()
  12.        
  13.     def push(self, value):
  14.         self.__stack.append(value)
  15.        
  16.     def empty(self):
  17.         return not bool(self.__stack)
  18.        
  19. class Queue:
  20.     def __init__(self):
  21.         self.__queue = deque()
  22.    
  23.     def enqueue(self, value):
  24.         self.__queue.append(value)
  25.        
  26.     def dequeue(self):
  27.         self.__queue.popleft()
  28.    
  29.     def top(self):
  30.         return self.__queue[0]
  31.    
  32.     def empty(self):
  33.         return not bool(self.__queue)
  34.    
  35.     def __iter__(self):
  36.         return iter(self.__queue)
  37.  
  38. precedence = {
  39.               "*" : 10,
  40.               "/" : 10,
  41.               "+" : 9,
  42.               "-" : 9,
  43.               "(" : -1,
  44.               ")" : -1,
  45.               }
  46.  
  47. operations = {
  48.               "*" : lambda x, y: x * y,
  49.               "/" : lambda x, y: x / y,
  50.               "+" : lambda x, y: x + y,
  51.               "-" : lambda x, y: x - y,
  52.               }
  53.  
  54. expr = ["3", "-", "(", "2", "+", "30", ")"]
  55.  
  56. def infixTOprefix(expr, precedence):
  57.     stack = Stack()
  58.     output = Queue()
  59.    
  60.     for token in expr:
  61.         if token not in precedence:
  62.             output.enqueue(token)
  63.         elif token == ")":
  64.             while not stack.empty():
  65.                 if stack.top() == "(":
  66.                     stack.pop()
  67.                     break
  68.                 else:
  69.                     output.enqueue(stack.top())
  70.                     stack.pop()
  71.         else:
  72.             if stack.empty() or token == "(":
  73.                 stack.push(token)
  74.             else:
  75.                 while not stack.empty() and precedence[token] <= precedence[stack.top()]:
  76.                     output.enqueue(stack.top())
  77.                     stack.pop()
  78.                 stack.push(token)
  79.    
  80.     while not stack.empty():
  81.         output.enqueue(stack.top())
  82.         stack.pop()
  83.     return list(output)
  84.  
  85. def evaluate(expr, operations):
  86.     stack = Stack()
  87.     for token in expr:
  88.         if token not in operations:
  89.             stack.push(float(token))
  90.         else:
  91.             a = stack.top()
  92.             stack.pop()
  93.             b = stack.top()
  94.             stack.pop()
  95.             stack.push(operations[token](b, a))
  96.     return stack.top()
  97.  
  98. prefix = infixTOprefix(expr, precedence)
  99. print expr
  100. print prefix
  101. print evaluate(prefix, operations)