계산기 구현

honeyricecake·2022년 2월 7일
0

자료구조

목록 보기
15/36

한자리수만 계산할 수 있고 중간까지의 계산값도 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
  1. 함수가 정의된 소스파일
#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);
}

0개의 댓글