후위연산의 정의와 코드 구현
후위연산의 정의와 필요
후위연산(Postfix Notation)은 연산자가 피연산자 뒤에 위치하는 표기법입니다.
중위 표기법보다 연산 순서를 쉽게 처리할 수 있어 컴퓨터가 계산하기에 유리합니다.
제가 방학 중 배우고 있는 자료구조 내용 중 하나로, 후위연산을 C언어로 구현해봤습니다.
후위연산의 특징
- 우선순위 불필요 : 연산자 우선순위를 따로 고려하지 않아도 됩니다.
- 괄호 불필요 : 연산 순서가 명확하므로 괄호를 사용할 필요가 없습니다.
- 스택 사용 : 주로 스택(Stack)을 활용하여 구현합니다.
예시 변환
중위식 (3 + 4) * 5 - 6
→ 후위식 3 4 + 5 * 6 -
계산 과정:
3 4 +
→7
7 5 *
→35
35 6 -
→29
후위연산 코드 작성 (C언어)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//후위표기식 1자리
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct {
int item[MAX_SIZE];
int top; // 1. 코드의 모듈화와 재사용성을 높이고 스택 관리의 안전성을 보장
}Stack;
void push(Stack* s, int add);
int pop(Stack* s);
int eval(char post[]); // 후위연산 계산함수
int Precedence(char c); // 우선순위 반환함수
void postfix(char* infix, char* postfix);
void Stack_Empty();
void Stack_Full();
먼저 헤더파일 선언 후 100개의 공간을 가진 item의 배열, top을 Stack구조체에 선언합니다.
그 후 전역변수로 top을 -1로 초기화를 한 후 필요한 함수들을 적었습니다.
main 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main()
{
char infix[MAX_SIZE];
char post[MAX_SIZE];
printf("중위식을 후위식으로 바꾸는 프로그램입니다.\n");
printf("중위식을 입력하시오 : ");
fgets(infix, sizeof(infix), stdin);
int len = strlen(infix);
if (len > 0 && infix[len - 1] == '\n') {
infix[len - 1] = '\0';
}
printf("\n입력한 중위 표기식 : %s",infix);
postfix(infix, post);
printf("\n변환한 후위 표기식 : %s", post);
int result = eval(post);
printf("\n계산 결과 : %d\n", result);
return 0;
}
함수를 작성하기 전 main함수를 작성하였습니다.
함수보다 main함수 먼저 작성하면 더 생각하기 편하더라구요..
c언어를 잘 사용하지 않다 보니까 문자열 입력받는 방법을 까먹었는데 다시 요약해보겠습니다.
fgets() 사용법 :
fgets(buffer, size, stream);
buffer : 문자열을 저장할 배열포인터
size : buffer의 최대 저장 가능한 문자 수
stream : 입력을 받을 스트림 지정 - 보통 ‘stdin’을 사용함.
fgets() 주의사항 :
fgets()는 개행문자(‘\n’)을 만나면 입력을 멈추지만 이 개행문자를 버퍼에 포함시킴.
이를 처리하기 위해 NULL문자로 대체하거나 제거해야함.## push함수
Stack의 기본 Push, pop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void Stack_Empty()
{
fprintf(stderr, "Stack is Empty!\n");
exit(1);
}
void Stack_Full()
{
fprintf(stderr, "Stack is Full!\n");
exit(1);
}
void push(Stack* s, int add)
{
if (s->top >= MAX_SIZE - 1)
{
Stack_Full();
return;
}
s->item[++(s->top)] = add;
}
int pop(Stack* s)
{
if (s->top == -1)
{
Stack_Empty();
s->top = -1;
}
return s->item[(s->top)--];
}
Stack의 기본 코드 push와 pop코드를 작성하였습니다.
postfix 변환 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void postfix(char* infix, char* postfix)
{
char postfix_index = 0; //후위연산 배열
char current; // 현재 문자
int len = strlen(infix);
Stack s;
s.top = -1;
for (int i = 0; i < len; i++)
{
current = infix[i];
switch (current)
{
case '+':
case '-':
case '*':
case '/':
case '%':// 현재문자가 연산자일 경우
while (s.top == -1 && Precedence(current) <= Precedence(s.item[s.top])) // top이 -1이거나 현재 연산자가 스택에 있는 연산자보다 우선순위가 낮으면
{
postfix[postfix_index++] = pop(&s);
}
push(&s, current);
break;
case '(':
push(&s, current);
break;
case ')':
while (s.item[s.top] != '(')
{
postfix[postfix_index++] = pop(&s);
}
pop(&s); //왼쪽괄호를 pop함
break;
default: //피연산자일 경우
postfix[postfix_index++] = current; //후위 표기식에 바로 삽입
break;
}
}
while (s.top != -1)
{
postfix[postfix_index++] = pop(&s);
}
postfix[postfix_index] = '\0';
}
가장 중요한 postfix함수…
main함수에서 infix(중위연산식) 배열을 입력받고 postfix로 변환하는 과정을 코드로 구현했습니다.
1
2
3
4
5
char postfix_index = 0; //후위연산 배열
char current; // 현재 문자
int len = strlen(infix);
Stack s;
s.top = -1;
먼저, postfix_index라는 변수를 선언 후 0으로 초기화합니다 . postfix_index는 새로운 후위연산식을 나타냅니다.
current는 입력받은 infix의 배열에서 현재 문자를 나타냅니다.
infix의 길이를 len에 저장 후 for문으로 0번째 인덱스부터 infix의 길이까지 연산을 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
current = infix[i];
switch (current)
{
case '+':
case '-':
case '*':
case '/':
case '%':// 현재문자가 연산자일 경우
while (s.top != -1 && Precedence(current) <= Precedence(s.item[s.top])) // top이 -1이 아니고 현재 연산자가 스택에 있는 연산자보다 우선순위가 낮으면
{
postfix[postfix_index++] = pop(&s);
}
push(&s, current);
break;
case '(':
push(&s, current);
break;
변환과정
연산자일 경우 : current(현재 문자)가 ‘+’, ‘-‘, ‘*’, ‘/’, %’일 경우에는 스택에 push를 합니다.
여기서 top이 -1이 아니고 current가 스택에 있는 연산자보다 우선순위가 낮을 경우에는 현재 스택에 들어있는 연산자를 먼저 pop을 하여 postfix에 넣습니다.
1
2
3
4
5
6
7
8
9
10
case '(':
push(&s, current);
break;
case ')':
while (s.item[s.top] != '(')
{
postfix[postfix_index++] = pop(&s);
}
pop(&s); //왼쪽괄호를 pop함
break;
괄호일 경우:
왼쪽 괄호 : 왼쪽괄호 나올 경우 무조건 스택에 push를 합니다.
오른쪽 괄호 : 오른쪽 괄호가 나올 경우 왼쪽괄호가 나올 때까지 pop을 하여 postfix배열에 넣습니다. 그 후 pop을 하여 왼쪽괄호도 제거합니다.
1
2
3
default: //피연산자일 경우
postfix[postfix_index++] = current; //후위 표기식에 바로 삽입
break;
피연산자일 경우 : 피연산자일 경우에는 후위표기식에 바로 삽입을 합니다.
1
2
3
4
5
중위식을 후위식으로 바꾸는 프로그램입니다.
중위식을 입력하시오 : 1+4*3
입력한 중위 표기식 : 1+4*3
변환한 후위 표기식 : 143*+
현재까지의 결과물입니다. 문제 없이 잘 출력되는 걸 볼 수 있습니다. 휴우.. ㄴㅇㅅ
이제 후위연산까지 잘 바꿨으니 계산을 해야겠죠?
마지막 하나 남은 eval함수를 작성해줍시다.
eval 함수 (후위연산 계산)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int eval(char* post){
Stack s;
int op1,op2;
int len = strlen(post);
s.top = -1;
for (int i = 0; i < len; i++)
{
char current = post[i];
if (current == ' ')
continue;
else if (current >= '0' && current <= '9')
{
push(&s, current - '0');
}
else{
op1 = pop(&s);
op2 = pop(&s);
switch (current)
{
case '+':
push(&s, op2 + op1);
break;
case '-':
push(&s, op2 - op1);
break;
case '*':
push(&s, op2 * op1);
break;
case '/':
push(&s, op2 / op1);
break;
}
}
}
return pop(&s);
}
eval함수 전체 코드입니다
1
2
3
4
5
6
7
char current = post[i];
if (current == ' ')
continue;
else if (current >= '0' && current <= '9')
{
push(&s, current - '0');
}
len의 길이만큼 for문을 돌린 후 post배열의 문자들을 current에 저장시킴.
만약 current가 공백일 경우엔 무시
current가 피연산자일 경우엔 정수로 변환 후 push
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
else{
op1 = pop(&s);
op2 = pop(&s);
switch (current)
{
case '+':
push(&s, op2 + op1);
break;
case '-':
push(&s, op2 - op1);
break;
case '*':
push(&s, op2 * op1);
break;
case '/':
push(&s, op2 / op1);
break;
}
}
연산자일 경우에는 pop을 하여 계산을 한다
주의사항 : op1을 먼저 꺼냈다 -> op1이 op2보다 스택 구조 상 위에 있다. -> 계산할 때 op2가 앞으로 가서 계산해야함.
1
return pop(&s);
마지막으로 pop을 하여 계산값을 main함수로 넘긴다.
1
2
int result = eval(post);
printf("\n계산 결과 : %d\n", result);
result에 저장 후 출력
1
2
3
4
5
6
중위식을 후위식으로 바꾸는 프로그램입니다.
중위식을 입력하시오 : 3*4+(3-2)+1
입력한 중위 표기식 : 3*4+(3-2)+1
변환한 후위 표기식 : 34*32-+1+
계산 결과 : 14
3·4+(3−2)+1을 계산했을 때 34*32−+1+으로 후위연산식으로 바뀐 후 14로 계산이 성공적으로 출력된다.