앞에서 구현한 코드를 클래스를 사용한 코드로 변환해 볼까요? 클래스 InfixExpression은 4개의 속성(infix, prefix, opStack, exprStack)을 갖습니다. 속성 infix(중위 수식)는 주 생성자(primary constructor)를 사용해 초기화합니다. 반면, 속성 prefix(전위 수식)는 메소드 infixToPrefix()를 실행하기 전까지는 빈 문자열입니다. precedence 등 내부에서만 사용하는 메소드는 private로 선언했습니다. 반면, 2개 메소드(infixToPrefix와 evaluatePrefix)는 public으로 선언하였으며, 외부에서 이 메소드를 직접 호출할 수 있습니다.
import java.util.Stack
import kotlin.math.pow
enum class Precedence (val priority: Int) { ... }
class InfixExpression(val infix: String) {
var prefix: String = ""
private val opStack = Stack<Char>()
private val exprStack = Stack<String>()
private fun precedence(op: Char): Int { ... }
private fun eval(op: Char, oprd1: Int, oprd2: Int) = ...
private fun processOperators(ch: Char) { ... }
private fun handleRemainingOperators() { ... }
fun infixToPrefix() { ... }
fun evaluatePrefix(): Int { ... }
}
앞에서 구현한 코드와 어떻게 달라졌는지 살펴보겠습니다. 먼저 아래 2개 메소드(precedence, eval)는 전혀 바뀌지 않았습니다.
private fun precedence(op: Char): Int {
return when (op) {
'+', '-' -> Precedence.LOW.priority
'*', '/' -> Precedence.MEDIUM.priority
'^' -> Precedence.HIGH.priority
else -> Precedence.NONE.priority
}
}
private fun eval(op: Char, oprd1: Int, oprd2: Int) =
when (op) {
'+' -> oprd1 + oprd2
'-' -> oprd1 - oprd2
'*' -> oprd1 * oprd2
'/' -> oprd1 / oprd2
'^' -> oprd1.toDouble().pow(oprd2.toDouble()).toInt()
else -> 0
}
반면, 아래 2개 메소드는 조금 달라졌습니다. 어디가 어떻게 바뀌었는지 확인해 보았나요? opStack과 exprStack은 모두 클래스 속성으로 선언했기 때문에, 함수의 형식 인자로 전달받을 필요가 없습니다.
private fun processOperators(ch: Char) {
while (opStack.isNotEmpty() &&
precedence(ch) < precedence(opStack.peek())
) {
val op = opStack.pop()
val operand1 = exprStack.pop()
val operand2 = exprStack.pop()
exprStack.push(op + operand2 + operand1)
}
opStack.push(ch)
}
private fun handleRemainingOperators() {
while (opStack.isNotEmpty()) {
val op = opStack.pop()
val operand1 = exprStack.pop()
val operand2 = exprStack.pop()
exprStack.push(op + operand2 + operand1)
}
}
클래스를 정의할 때 어느 메소드를 private 또는 public으로 선언할지 결정해야 합니다. 중위 수식을 전위 수식으로 변환하는 메소드 infixToPrefix와 전위 수식을 계산하는 evaluatePrefix는 public으로 선언하는 것이 바람직합니다. 이 2개의 메소드는 달라진 부분이 없으므로 자세한 코드는 생략합니다.
fun infixToPrefix() { ... }
fun evaluatePrefix(): Int { ... }
이제 main() 함수를 살펴보겠습니다. 클래스 InfixExpression의 속성 infix를 초기화해 객체 evaluator를 생성합니다. 객체 evaluator의 메소드 infixToPrefix()를 실행해 중위 수식을 전위 수식으로 변환하고, 변환 결과를 속성 prefix에 저장합니다. 객체 evaluator의 메소드 evaluatePrefix()를 실행해 전위 수식을 계산합니다.
fun main() {
val infix = "3 + 2 * 4"
val evaluator = InfixExpression(infix)
evaluator.infixToPrefix()
val result = evaluator.evaluatePrefix()
println("${evaluator.prefix} = $result")
}
'코틀린' 카테고리의 다른 글
코틀린: 6장 스레드와 코루틴 - 오류 정정 (0) | 2025.01.09 |
---|---|
코틀린: infix expression을 prefix expression으로 변환(5/5) - 괄호 처리 (0) | 2025.01.09 |
코틀린: infix expression을 prefix expression으로 변환(3/5) - 람다 식 (0) | 2025.01.09 |
코틀린: infix expression을 prefix expression으로 변환(2/5) - List 구현 (0) | 2025.01.09 |
코틀린: infix expression을 prefix expression으로 변환(1/5) - 문자열 방식 (0) | 2025.01.09 |