후위표기법 계산기 기초개념 및 구현실습
.
그림, 실습코드 등 학습자료 출처 : https://github.com/ythwork
- 우리가 아는 계산기의 방식은 중위 표기법이다.
ex) (2 + 5) * 3 / (9 - 7)
- 반면에 컴퓨터가 이해하기 쉬운 계산법은 후위표기법이다.
컴퓨터가 연산하는 과정을 시뮬레이션 한 계산기라고도 할 수 있다.
괄호가 없고, 연산자가 뒤로 가는 것이 특징이다.
ex) 2 5 + 3 * 2 1 + *
이 수식을 푸는 과정
- 후위표기법 계산기 작동예시
(2 + 5) * 3 * (2 + 1) 를 예로들자
먼저 최초 계산에 필요한 요소 셋팅한다.
1) listExp = []
(먼저 최종 후위 수식을 담을 수식리스트)
2) Stack = []
(연산자 가중치에 따라 수식의 요소들을 담을 스택리스트)
그 다음에 각 연산자에 대해 가중치를 책정해둔다.
1) 곱하기, 나누기 : 가중치를 크게 설정
2) 더하기, 빼기 : 가중치를 중간정도 설정
3) 괄호 : 가중치를 가장 작게 설정
예를 들어서 ( 또는 ) 를 말한다.
그 다음에 주어진 수식을 listExp에 담는 작업을 해준다.
listExp에 담겨진 후위표기식을 계산하는 작업을 아래의 그림과 같이 해준다.
- 후위표기법 계산기 구현을 위한 stack 클래스 구현
class Node:
def __init__(self, data=None):
self.__data=data
self.__next=None
@property
def data(self):
return self.__data
@data.setter
def data(self, data):
self.__data=data
@property
def next(self):
return self.__next
@next.setter
def next(self, n):
self.__next=n
class stack:
def __init__(self):
self.top=None
def empty(self):
if self.top is None:
return True
else:
return False
def push(self, data):
new_node = Node(data)
if self.empty():
self.top = new_node
return
new_node.next = self.top
self.top=new_node
def pop(self):
if self.empty():
return None
cur = self.top
self.top = self.top.next
return cur.data
def peek(self):
if self.empty():
return None
return self.top.data
if __name__ =="__main__":
s = stack()
s.push(1)
s.push(2)
s.push(3)
s.push(4)
s.push(5)
while not s.empty():
print(s.pop(), end=" ")
5 4 3 2 1
- stack 클래스를 이용한 후위표기 계산기 구현
class Calculator:
def __init__(self):
self.org_exp=None
self.postfix_exp=None
self.result=None
def set_org_exp(self, org_exp):
self.org_exp=org_exp.replace(' ', '')
## org_exp 중위표기법
## ==> 유저에게 입력 받으며 공백을 삭제하여 저장한다
self.postfix_exp=None
## postfix_exp 후위표기법
## ==> 유저에게 입력 받은 중위 표기법을 후위 표기법으로 변경하여 저장한다.
self.result=None
def get_org_exp(self):
return self.org_exp
def get_weight(self, oprt):
## 인자로 받은 연산자의 가중치를 리턴한다.
## 가중치 순서 : *, / > +, - > (
if oprt=='*' or oprt=='/':
return 9
elif oprt=='+' or oprt=='-':
return 7
elif oprt=='(':
return 5
def convert_to_postfix(self):
## 인스턴스 변수 org_exp를 후위표기법으로 변경하여 postfix_exp 변수에 저장한다.
## 가중치에 따라서 연산자를 담을 스택과, 최종 후위 수식을 담을 리스트를 활용한다.
exp_list=[]
oprt_stack=stack()
for ch in self.get_org_exp(): ## get_orp_exp()에서 입력받은 것들을 for문으로 돌아라
if ch.isdigit(): ## 숫자라면 exp_list에 넣어주고
exp_list.append(ch)
else: ## 연산자 문자열이라면
if oprt_stack.empty() or ch=='(': ## 스텍안이 비어있거나 ( 라면
oprt_stack.push(ch) ## oprt_stack에 push해라
elif ch==')': ## ) 라면
op=oprt_stack.pop() ## oprt_stack에서 pop해라
while op!='(': ## ( 가 나오기 전까지 계속해서
exp_list.append(op) ## exp_list에 넣어주고
op=oprt_stack.pop() ## oprt_stack에서 pop해라
else: ## + - / 이라면
if self.get_weight(ch) > self.get_weight(oprt_stack.peek()):
## 피크로 확인해서 가중치를 서로 비교해서 새로 가져온게 oprt_stack.peek()보다크면
## oprt_stack으로 새로 가져온 것을 push해라
oprt_stack.push(ch)
else: ## oprt_stack.peek()보다 가중치가 작거나 같으면
while not oprt_stack.empty() and self.get_weight(ch) <= self.get_weight(oprt_stack.peek()):
exp_list.append(oprt_stack.pop())
oprt_stack.push(ch)
while not oprt_stack.empty():
exp_list.append(oprt_stack.pop())
self.postfix_exp=''.join(exp_list) ## postfix_exp에 문자열로 join해서 넣어라
def get_postfix_exp(self):
## postfix_exp 변수에 담긴 값을 리턴한다. 없다면 convert_to_postfix()을 실행한다.
if not self.org_exp:
return None
if not self.postfix_exp:
self.convert_to_postfix()
return self.postfix_exp
def calc_two_oprd(self, oprd1, oprd2, oprt):
## 연산자의 종류에 따라서 연산을 진행한 결과를 리턴한다.
if oprt=='+':
return oprd1+oprd2
elif oprt=='-':
return oprd1-oprd2
elif oprt=='*':
return oprd1*oprd2
elif oprt=='/':
return oprd1//oprd2
def calculate(self):
## postfix_exp 변수에 담긴 후위수식 값을 연산한 결과를 리턴한다.
oprd_stack=stack()
for ch in self.get_postfix_exp():
if ch.isdigit():
oprd_stack.push(int(ch))
else :
oprd2=oprd_stack.pop()
oprd1=oprd_stack.pop()
oprd_stack.push(self.calc_two_oprd(oprd1, oprd2, ch))
self.result=oprd_stack.pop()
def get_result(self):
if not self.org_exp:
return None
if not self.result:
self.calculate()
return self.result
if __name__=="__main__":
calc=Calculator()
while True:
exp=input("수식을 입력하세요 (종료:0):")
if exp=='0':
break
calc.set_org_exp(exp)
print(calc.get_postfix_exp())
print('{exp}={result}'.format(exp=calc.get_org_exp(), result=calc.get_result()))
수식을 입력하세요 (종료:0):2+4
24+
2+4=6
수식을 입력하세요 (종료:0):9-7
97-
9-7=2
수식을 입력하세요 (종료:0):5*4
54*
5*4=20
수식을 입력하세요 (종료:0):8/4
84/
8/4=2
수식을 입력하세요 (종료:0):0