1. 설계 및 코드
1)연산 클래스
-연산클래스를 추상화한 AbstractOperation 클래스를 만들은 뒤 AddOperation(더하기), SubstractOperation(빼기), MultiplyOperation(곱하기), DivideOperation(나누기) 클래스들을 만들어 AbstractOperation을 상속받고 각 연산 메소드를 오버라이드 하도록 함.
open class AbstractOperation() {
open fun operation(num1:Int, num2:Int):Int{return 0}
}
class AddOperation():AbstractOperation() {
override fun operation(num1:Int, num2:Int):Int {
return num1 + num2
}
}
2) Calculator 클래스
<1>postfix: 입력받은 수식 String을 연산자와 피연산자 단위로 분해하고 infix형태의 순서를 postfix형태로 변환하는 메소드. 스택을 이용
fun postfix(exp:String):Array<Any>{
val stack= Stack<String>()
var arr= arrayOf<Any>()
var order=mapOf<String,Int>("(" to 0,"+" to 1, "-" to 1, "*" to 2, "/" to 2, "%" to 2)
//수식을 피연산자와 연산자들의 배열로 변환
val oplist=arrayOf<String>("+","-","*","/","%","(",")")
val expArr=exp.toCharArray()
var explist= arrayOf<String>()
var tmp=StringBuilder()
for(i in expArr){
val tmpi=i.toString()
if(oplist.contains(tmpi)){
if(!tmp.isEmpty()){
explist+=tmp.toString()
tmp.clear()
}
explist+=tmpi
}
else{
tmp.append(i)
}
}
//마지막 남은 숫자들 있으면 추가
if(!tmp.isEmpty()){
explist+=tmp.toString()
}
for(i in explist){
if(oplist.contains(i)){
if(stack.empty()){
stack.push(i)
}else if(i=="("){
stack.push(i)
}
else if(i==")"){
while(stack.peek()!="("){
arr+=stack.pop()
}
stack.pop()
}
else if(order[stack.peek()]!!>=order[i]!!){
while (order[stack.peek()]!!>=order[i]!!){
arr+=stack.pop()
if(stack.isEmpty()){
break
}
}
stack.push(i)
}
else{
stack.push(i)
}
}
else{
arr+=i.toInt()
}
}
while(!stack.empty()){
arr+=stack.pop()
}
return arr
}
-규칙(결과는 배열)
[1] 숫자는 바로 배열로 넘겨줌
[2] 연산자의 경우
-스택이 비어있으면 스택에 넣음
-스택이 비어있지 않은 경우 아닌경우
- 여는 괄호인 경우 일단 스택에 넣음
- 닫는 괄호인 경우 여는 괄호가 나올때까지 스택의 원소들을 차례로 pop하여 배열에 넣어줌. 괄호는 배열에 넣지 않음
- 괄호가 아닌경우:
- 스택 맨위의 연산자가 현재 연산자 보다 우선순위가 높거나 같은 경우: 스택내에 현재 연산자 이상의 우선순위를 가진 연산자가 남아있지 않을때 까지 pop해서 배열로 옮긴다. 이후 스택에 현재 연산자를 push함
- 아닌경우 바로 현재 연산자를 push
[3]for을 다 돈 뒤 스택에 남아있는 연산자들은 모두 pop해서 배열로 넘김
[4]최종적으로 배열이 postfix형태 수식이 된다.
<2>calculation:postfix형태의 수식배열을 이용하여 결과값 도출.
-postfix 메소드를 이용하여 문자열 형태 중위표현식을 배열로 토큰화된 형태의 후위표현식으로 바꿔줌.
-스택을 이용하여 계산:숫자는 계속 스택에 넣다가 연산자가 나오면 스택 맨 위의 두 숫자를 pop해 연산후 스택에 다시 넣기 반복
fun calculation(s:String):Int{
var stack= Stack<Int>()
val arg=postfix(s)
for(i in arg){
if(i is Int){
stack.push(i)
}
else{
val post=stack.pop()
val pre=stack.pop()
stack.push(operation(pre,post, i as String))
}
}
return stack.pop()
}
<3>Calculator 전체 코드
package com.example.calculator
import java.util.*
class Calculator() {
val add=AddOperation()
val sub=SubstractOperation()
val mul=MultiplyOperation()
val div=DivideOperation()
fun operation(num1:Int,num2:Int,op:String):Int{
if(op=="%"){
return num1%num2
}
else{
val obj=when(op){
"+" ->add
"-" ->sub
"*" ->mul
else -> div
}
return obj.operation(num1, num2)
}
}
fun postfix(exp:String):Array<Any>{
val stack= Stack<String>()
var arr= arrayOf<Any>()
var order=mapOf<String,Int>("(" to 0,"+" to 1, "-" to 1, "*" to 2, "/" to 2, "%" to 2)
//수식을 피연산자와 연산자들의 배열로 변환
val oplist=arrayOf<String>("+","-","*","/","%","(",")")
val expArr=exp.toCharArray()
var explist= arrayOf<String>()
var tmp=StringBuilder()
for(i in expArr){
val tmpi=i.toString()
if(oplist.contains(tmpi)){
if(!tmp.isEmpty()){
explist+=tmp.toString()
tmp.clear()
}
explist+=tmpi
}
else{
tmp.append(i)
}
}
//마지막 남은 숫자들 있으면 추가
if(!tmp.isEmpty()){
explist+=tmp.toString()
}
for(i in explist){
if(oplist.contains(i)){
if(stack.empty()){
stack.push(i)
}else if(i=="("){
stack.push(i)
}
else if(i==")"){
while(stack.peek()!="("){
arr+=stack.pop()
}
stack.pop()
}
else if(order[stack.peek()]!!>=order[i]!!){
while (order[stack.peek()]!!>=order[i]!!){
arr+=stack.pop()
if(stack.isEmpty()){
break
}
}
stack.push(i)
}
else{
stack.push(i)
}
}
else{
arr+=i.toInt()
}
}
while(!stack.empty()){
arr+=stack.pop()
}
println(arr.contentToString())
return arr
}
fun calculation(s:String):Int{
var stack= Stack<Int>()
val arg=postfix(s)
for(i in arg){
if(i is Int){
stack.push(i)
}
else{
val post=stack.pop()
val pre=stack.pop()
stack.push(operation(pre,post, i as String))
}
}
return stack.pop()
}
}
3) Main함수
fun main(){
while(true){
println("수식을 입력해 주세요(종료하려면 -1입력)")
var exp= readLine().toString()
if(exp=="-1"){
break
}
val calculator=Calculator()
println("결과: ${calculator.calculation(exp)}")
}
println("종료되었습니다")
}
2. 실행 결과
3. 느낀점
추가로 넣은 기능인 수식 입력 및 계산이 조금 까다로웠다. infix를 postfix로 바꾸는 방법을 명확히 적어둔 곳이 없어서 여러군데를 확인하며 설계하는것이 번거로웠지만 그 외에는 수월하게 만들 수 있었던것 같다.
'코틀린 개인 과제' 카테고리의 다른 글
회원가입 MVVM 과제 (0) | 2024.07.14 |
---|---|
챌린지반 3주차 첫번째 과제: 디자인 패턴 구현 (0) | 2024.07.09 |
로그인 앱 제작-2 (0) | 2024.06.25 |
로그인 앱 제작 (0) | 2024.06.19 |
키오스크 제작 (0) | 2024.06.13 |