한자리수만 계산할 수 있고 중간까지의 계산값도 0이상의 정수여야만 하는 조잡한 계산기 ㅋㅋ...
스택 공부를 했다는데 의의를 두고자 한다..
내 코드
#include <stdio.h>
#include <string.h>
# define len 101
typedef struct
{
char list[len];
int top;
}Stack;
void Init(Stack* pstack)
{
pstack->top = -1;
}
void Insert(Stack* pstack, char data)
{
pstack->list[++(pstack->top)] = data;
}
int pop(Stack* pstack)
{
if (pstack->top < 0) return -1;
else return pstack->list[(pstack->top)--];
}
int peek(Stack* pstack)
{
if (pstack->top < 0) return -1;
else return pstack->list[pstack->top];
}
int Calculate(char* array)
{
int length = strlen(array);
int i;
Stack stack;
Stack* pstack = &stack;
Init(pstack);
for (i = 0; i < length; i++)
{
Insert(pstack, array[i]);
if (pstack->list[pstack->top] == '+')
{
pstack->list[pstack->top - 2] += (pstack->list[pstack->top - 1] - '0');
pstack->top -= 2;
}
else if (pstack->list[pstack->top] == '-')
{
pstack->list[pstack->top - 2] -= (pstack->list[pstack->top - 1] - '0');
pstack->top -= 2;
}
else if (pstack->list[pstack->top] == '*')
{
pstack->list[pstack->top - 2] = (pstack->list[pstack->top - 2] - '0') * (pstack->list[pstack->top - 1] - '0') + '0';
pstack->top -= 2;
}
else if (pstack->list[pstack->top] == '/')
{
pstack->list[pstack->top - 2] = (pstack->list[pstack->top - 2] - '0') / (pstack->list[pstack->top - 1] - '0') + '0';
pstack->top -= 2;
}
else continue;
}
return (pop(pstack) - '0');
}
int Position(char x, char y)//x가 stack의 아래에, y가 stack의 위에 있는 연산자
{
if (Prior(x) >= Prior(y)) return 1; //stack의 아래에 있는 것이 우선순위가 더 높으므로 stack의 top을 result문자열로
else return 0;
}
int Prior(char x)
{
if (x == '*' || x == '/') return 2;
else if (x == '+' || x == '-') return 1;
else if (x == '(') return 0;
}
int main()
{
Stack stack;
Stack* pstack = &stack;
Init(pstack);
char array[len] ={0};
char result[len] = {0};
int i;
int count = 0;
scanf("%s", array);
int length = strlen(array);
for (i = 0; i < length; i++)
{
if (48 <= array[i]) result[count++] = array[i];
else
{
if (42 <= array[i])
{
if (pstack->top == -1) Insert(pstack, array[i]);
else
{
while ((pstack->top) + 1)
{
if (Position(pstack->list[pstack->top], array[i]))
{
result[count++] = pop(pstack);
}
else break;
}
Insert(pstack, array[i]);
}
}
else if (array[i] == '(') Insert(pstack, array[i]);
else
{
while (pstack->list[pstack->top] != '(')
{
result[count++] = pop(pstack);
}
pop(pstack);
}
}
}
while ((pstack->top) + 1)
{
result[count++] = pop(pstack);
}
printf("%d",Calculate(result));
return 0;
}
강의의 코드
1.헤더파일
#ifndef __POST_CALCULATOR_H_
#define __POST_CALCULATOR_H_
int EvalRPNExp(char exp[]);
#endif
#include <string.h>
#include <ctype.h>
#include "ListBaseStack.h"
int EvalRPNExtp(char exp[])
{
Stack stack;
int expLen = strlen(exp);
int i;
char tok, op1, op2;
StackInit(&stack);
for(i = 0; i < explen; i++)
{
tok = exp[i];
if(isdigit(tok))//문자가 숫자이면 0이 아닌 숫자를 return하는 함수
{
SPush(&stack, tok - '0'); //숫자로 반환하여 push한다.
}
else//tok가 즉, 문자열의 i번째 칸의 문자가 연산자일 때
{
op2 = SPop(&stack);
op1 = SPop(&stack); // 먼저 꺼낸 값이 두번째 피연산자이다. 뺄셈과 나눗셈에서는 이 구분이 명확해야한다.
switch(tok)
{
case '+' :
SPush(&stack, op1 + op2);//숫자 2개를 빼고 두개를 연산한 숫자를 Push
break;
case '-' :
SPush(&stack, op1 - op2);
break;
case '#' :
SPush(&stack, op1 * op2);
break;
case '/' :
SPush(&stack, op1 / op2);
break;
}
}
}
return SPop(&stack);
}
<복습>
강의의 중위표기식을 후위표기식으로 바꾸는 코드
소스파일
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "ListBaseStack.h"
int GetOpPrec(char op)
{
switch(op)
{
case '*':
case '/':
return 5;
case '+':
case '-':
return 3;
case '(':
return 1;
}
return -1;//else를 따로 쓰지 않는 이유 : 위의 경우에 걸리면 모두 정수를 return하며 함수가 종료되기 때문
}
int WhoPrecop(char op1, op2)
{
int op1prec = GetOpPrec(op1);
int op2prec = GetOpPrec(op2);
if(op1Prec > op2Prec) return 1;
else if(op1Prec < op2Prec) return -1;
else return 0;//두 연산자의 우선 순위가 같을 때
}
void ConvToRPNExp(char exp[])
{
Stack stack;
int expLen = strlen(exp);
char* convExp = (char*)malloc(expLen + 1); // 메모리를 아까기 위해 동적할당 사용, explen + 1인 이유는 마지막의 널문자 때문
int i, idx = 0;
char tok, popOp;
memset(convExp, 0, sizeof(char)*(expLen+1));//강의에서 준 코드에는 expLen + 1에 괄호가 안 쳐져있는데 이러면 정말 만~에 하나 sizeof(char)가 1이 아니라면 오류가 났을 것
StackInit(&stack);
for(i = 0; i < explen, i++)
{
tok = exp[i];
if(idigit(tok))
{
convExp[idx++] = tok;
}
else
{
switch(tok)//윤성우 선생님께서 switch함수를 참 좋아하시는 듯하다 ㅋㅋ
{
case '(':
SPush(&stack, tok);
break;
case ')' :
while(1)
{
popOp = SPop(&stack);
if(popOp == '(') break;//'('이면 break되므로 괄호는 스택에 쌓이지 않는다.
convExp[idx++] = popOp;//idx는 내 코드의 count같은 변수
}
break;
case '+' : case '-' :
case '#' : case '/' :
while(!SIsEmpty(&stack) && WhoPrecOp(SPeek(&stack), tok) >= 0)
//스택이 비어있지 않고, 스택의 천장에 있는 연산자가 우선순위가 tok보다 높거나 같은 동안(스택의 천장에 있는 연산자와 tok가 우선순위가 같으면 스택의 천장에 있는 연산자가 식에서 먼저 나온 것이므로 우선순위가 더 높다)
convExp[idx++] = SPop(&stack);
SPush(&stack, tok);
break;
}
}
}//여기까지 반복문
while(!SIsEmpty(&stack)) convExp[idx++] = SPop(&stack);//반복문을 끝내고 스택 비우기
strcpy(exp, convExp);
free(convExp);
}