비주얼베이직 수업 시간에 했던 후위 표기법을 이용한 사칙연산 계산기 과제이다
코딩 공부를 할 때 보통 if else 문을 이용한 계산기 만들기를 자주 할것인데
우리가 일반적으로 사용하는 계산기랑은 다른걸 그냥 봐도 알것이다
아래 방법은 우리가 일반적으로 사용하는 계산기를 만들어보는 방법이다
1 + 5 * 3 을 계산하려고 한다면 우리는 해당 수식을 바꿔야한다
이 때 배열과 스택을 사용하는데
배열에는 숫자, 스택에는 연산자를 넣는다고 생각하면 된다
예를 들어보자
1 + 5 * 3 - 2 라는 수식을 계산해야한다 우리는 연산자 우선순위에 의해서
곱하기를 먼저하고 그 다음 + 나 -를 하는 것을 알고 있다
그래서 다음과같은 규칙을 적용한다
수식을 문자열이라고 하자
문자열의 0번째 인덱스부터 읽기 시작하는데
1. 숫자면 배열에 추가한다.
2. 곱하기 또는 나누기면 스택에 추가한다.
3. 더하기 또는 빼기면 현재 스택에 담겨있는 연산자를 전부 pop 하여 순서대로 배열에 추가하고
읽었던 연산자를 스택에 추가한다.
4. 문자열을 전부 읽었으면 스택에 남아있는 연산자를 전부 pop 하여 순서대로 배열에 추가한다.
차례대로 해보자
먼저 문자열 첫번째를 읽는다.
숫자다.
배열에 넣는다.
그다음 +다
더하기 연산자 기호이다
스택에 있는 모든걸 배열에 차례대로 넣고 +를 넣는다
그런데 스택에 아무것도 없다
그냥 넣는다
그다음 숫자다 배열에 넣는다
그 다음 곱하기 연산자다 스택에 넣는다
그 다음 숫자다 배열에 넣는다
그 다음 빼기 연산자 기호이다.
스택에 있는걸 차례대로 배열에 넣는다
빼기 까지 스택에 넣어주고 문자열의 다음 인덱스를 읽는다 숫자다
배열에 넣는다
근데 문자열의 마지막 인덱스였다
그러면 스택에 남아있는 연산자를 배열에 넣는다
그러면 만들어지는 문자열은 153*+2- 이게 후위 표기법이다
그러면 후위표기법으로 어떻게 연산을 하는가
후위 표기법으로 만들어진 문자열을 첫번째부터 읽기시작한다
그리고 다음 규칙을 적용한다
문자열을 읽다가 기호를 만나면 기호 바로 전 숫자와 그 전숫자를 기호에 해당하는 연산을 하고 그 전숫자의 인덱스에 결과를 저장하고 기호와 기호 앞 인덱스를 배열에서 삭제한다. 이걸 인덱스가 하나일때까지 반복한다.
말이 어렵다 그림으로 보자
숫자다 넘어간다
또 숫자다 넘어간다
또 숫자다 넘어간다
곱하기 기호이다
그러면 3과 5를 * 연산을 해준다 그리고 그걸 5가 있던 자리에 넣고 3과 *은 삭제한다 배열에서 통째로
메모리 주소를 사용하는 배열 기본 배열을 사용하려면 뒷원소들을 앞으로 당겨주는 연산이 필요하고
동적배열을 이용하면 삭제해주면 된다
그리고 다시 처음부터 읽기 시작한다
숫자다 넘어가자
또 숫자다 넘어가자
더하기 기호이다 그러면 1과 15를 +로 연산해주고 또 삭제해주면된다
숫자다 넘어가자
숫자다 넘어가자
마이너스 기호이다 그러면 16과 2를 - 해주면된다 여기서 순서를 정확히 지켜야함
야호 배열의 길이는 1개 반복 끝! 그러면 결과는 14!
1 + 3 * 5 - 2 의 결과는? 14!!
만약 () 기호가 있을경우 ( 기호를 만나면 배열과 스택을 하나 더 만들어서 )가 나올때까지 새로만든 배열과 스택에 넣으면된다 )를 만나면 새로운 스택을 새로운 배열에 넣고 새로운 배열을 원래 배열에 넣으면 된다
비주얼 베이직으로 후위표기법 변환 코드를 작성하면 이렇게 된다
배우면서 적은거라 당연히 최적화는 제대로 되있지도 않지만 그냥 아 대충 이렇게 하는거구나 참고만 하면 좋을듯 합니다
연산을 하는 코드는 스위치 케이스문을 사용하던지 if else 를 사용하던지 자
https://github.com/wndudwkd003/va-calculate-example
Imports Accessibility
Public Class Form1
Public Structure Calculator
Dim numberArr As ArrayList
Dim signStack As Stack
End Structure
Dim bkCalulators As New ArrayList
Dim InputStringArr As New ArrayList
Dim InputString As String = ""
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim calculatorInstance As New Calculator With {
.numberArr = New ArrayList,
.signStack = New Stack
}
bkCalulators.Add(calculatorInstance)
Label_window.Text = InputString
End Sub
Private Sub Button_n_0_Click(sender As Object, e As EventArgs) Handles Button_n_0.Click
setLabelWindowIS("0")
End Sub
Private Sub setLabelWindowIS(v As String)
'입력 조건
'최대 길이 제한
If InputString.Length < 29 * 2 Then
If InputString.Length = 0 And Not IsNumeric(v) Then
'첫입력에 기호가 오면
If v = "(" Then
InputString = InputString & v
Else
Return
End If
ElseIf InputString.Length > 0 And Not IsNumeric(v) Then
If Not v = "(" And Not v = ")" And Not InputString.Last = "(" And Not InputString.Last = ")" And Not IsNumeric(InputString.Last) Then
Dim tmp As String = ""
Dim i As Integer
'기호뒤에 기호가오면 맨끝 기호 대신 새로운 기호를 넣음
For i = 0 To InputString.Length - 2 Step 1
tmp = tmp & (InputString(i))
Next i
'기호 추가 전 입력된 문자열에 새로 입력된 기호 추가
InputString = tmp & v
Else
'그냥 기호 입력
InputString = InputString & v
End If
Else
'문제 없으면 문자열 뒤에 추가
InputString = InputString & v
End If
Label_window.Text = InputString
Else
MsgBox("최대 58개만 입력할 수 있습니다. " + vbCrLf + "더이상 입력할 수 없습니다.", 0, "경고")
End If
End Sub
Private Sub Button_n_1_Click(sender As Object, e As EventArgs) Handles Button_n_1.Click
setLabelWindowIS("1")
End Sub
Private Sub Button_n_2_Click(sender As Object, e As EventArgs) Handles Button_n_2.Click
setLabelWindowIS("2")
End Sub
Private Sub Button_n_3_Click(sender As Object, e As EventArgs) Handles Button_n_3.Click
setLabelWindowIS("3")
End Sub
Private Sub Button_n_4_Click(sender As Object, e As EventArgs) Handles Button_n_4.Click
setLabelWindowIS("4")
End Sub
Private Sub Button_n_5_Click(sender As Object, e As EventArgs) Handles Button_n_5.Click
setLabelWindowIS("5")
End Sub
Private Sub Button_n_6_Click(sender As Object, e As EventArgs) Handles Button_n_6.Click
setLabelWindowIS("6")
End Sub
Private Sub Button_n_7_Click(sender As Object, e As EventArgs) Handles Button_n_7.Click
setLabelWindowIS("7")
End Sub
Private Sub Button_n_8_Click(sender As Object, e As EventArgs) Handles Button_n_8.Click
setLabelWindowIS("8")
End Sub
Private Sub Button_n_9_Click(sender As Object, e As EventArgs) Handles Button_n_9.Click
setLabelWindowIS("9")
End Sub
Private Sub Button_t_3_Click(sender As Object, e As EventArgs) Handles Button_t_3.Click
InputStringArr.Clear()
InputString = ""
Label_window.Text = InputString
Label_1.Text = InputString
End Sub
Private Sub Button_t_4_Click(sender As Object, e As EventArgs) Handles Button_t_4.Click
If InputString.Length > 0 Then
InputString = InputString.Remove(InputString.Length - 1)
Label_window.Text = InputString
Else
Label_window.Text = InputString
End If
End Sub
Private Sub Button_t_1_Click(sender As Object, e As EventArgs) Handles Button_t_1.Click
setLabelWindowIS("(")
End Sub
Private Sub Button_t_2_Click(sender As Object, e As EventArgs) Handles Button_t_2.Click
setLabelWindowIS(")")
End Sub
Private Sub Button_t_5_Click(sender As Object, e As EventArgs) Handles Button_t_5.Click
setLabelWindowIS("+")
End Sub
Private Sub Button_t_6_Click(sender As Object, e As EventArgs) Handles Button_t_6.Click
setLabelWindowIS("-")
End Sub
Private Sub Button_t_7_Click(sender As Object, e As EventArgs) Handles Button_t_7.Click
setLabelWindowIS("×")
End Sub
Private Sub Button_t_8_Click(sender As Object, e As EventArgs) Handles Button_t_8.Click
setLabelWindowIS("÷")
End Sub
Private Sub setNumberArrFromStack(numberArr As ArrayList, signStack As Stack)
Dim i As Integer
For i = 0 To signStack.Count - 1 Step 1
numberArr.Add(signStack.Pop)
Next i
End Sub
Private Sub Button_t_result_Click(sender As Object, e As EventArgs) Handles Button_t_result.Click
'일단 기본적인것만 우선 오류제어
If InputString = "" Then
Return
ElseIf Not IsNumeric(InputString(InputString.Length - 1)) Then
Select Case InputString(InputString.Length - 1)
Case "+"
Return
Case "-"
Return
Case "×"
Return
Case "÷"
Return
End Select
End If
'입력된 식 분리하기
setInputStringArr()
'원본 계산식 저장 생성
Dim openBracket As Integer = 0
'후위 표기법 변환
Dim i As Integer
For i = 0 To InputStringArr.Count - 1 Step 1
If IsNumeric(InputStringArr(i)) Then
' 숫자면 그냥 넣음
bkCalulators(openBracket).numberArr.Add(InputStringArr(i))
Else
'기호면 몇개 체크해야함
If InputStringArr(i) = "(" Then
'괄호가 열리면
openBracket += 1
Dim calculatorInstance As New Calculator With {
.numberArr = New ArrayList,
.signStack = New Stack
}
bkCalulators.Add(calculatorInstance)
ElseIf InputStringArr(i) = ")" Then
'괄호가 닫히면 삭제
setNumberArrFromStack(bkCalulators(openBracket).numberArr, bkCalulators(openBracket).signStack)
'이전 배열로 다 추가
Dim u As Integer
For u = 0 To bkCalulators(openBracket).numberArr.Count - 1 Step 1
bkCalulators(openBracket - 1).numberArr.Add(bkCalulators(openBracket).numberArr(u))
Next u
bkCalulators.RemoveAt(openBracket)
openBracket -= 1
ElseIf bkCalulators(openBracket).signStack.Count = 0 And (InputStringArr(i) = "+" Or InputStringArr(i) = "-") Then
'스택의 처음 +-이런건 그냥 넣음
bkCalulators(openBracket).signStack.Push(InputStringArr(i))
ElseIf InputStringArr(i) = "+" Or InputStringArr(i) = "-" Then
'그다음 +-는 스택이랑 교환
setNumberArrFromStack(bkCalulators(openBracket).numberArr, bkCalulators(openBracket).signStack)
bkCalulators(openBracket).signStack.Clear()
bkCalulators(openBracket).signStack.Push(InputStringArr(i))
ElseIf InputStringArr(i) = "×" Or InputStringArr(i) = "÷" Then
'*/는 스택에 넣음
bkCalulators(openBracket).signStack.Push(InputStringArr(i))
End If
End If
Next i
'마지막 스택에 있는거 다넣음
setNumberArrFromStack(bkCalulators(openBracket).numberArr, bkCalulators(openBracket).signStack)
'후위연산 출력
Dim tmp As String = ""
For i = 0 To bkCalulators(openBracket).numberArr.Count - 1 Step 1
tmp = tmp & bkCalulators(openBracket).numberArr(i)
Next
Label_1.Text = tmp
'실제 계산
'늦은바인딩에러떠서 배열을 새로만들어야함
Dim result As New ArrayList
result = setResultNumberArr(bkCalulators(openBracket).numberArr)
Label_window.Text = CStr(result(0))
bkCalulators(openBracket).numberArr.Clear()
bkCalulators(openBracket).signStack.Clear()
result.Clear()
InputStringArr.Clear()
InputString = ""
End Sub
Private Function setResultNumberArr(numberArr As ArrayList) As ArrayList
'계산해서 배열 반환
Dim tmp As Integer = 0
Dim i As Integer = 0
While Not numberArr.Count = 1
If Not IsNumeric(numberArr(i)) Then
Select Case numberArr(i)
Case "+"
tmp = CInt(numberArr(i - 2)) + CInt(numberArr(i - 1))
Case "-"
tmp = CInt(numberArr(i - 2)) - CInt(numberArr(i - 1))
Case "×"
tmp = CInt(numberArr(i - 2)) * CInt(numberArr(i - 1))
Case "÷"
tmp = CInt(numberArr(i - 2)) \ CInt(numberArr(i - 1))
End Select
numberArr(i - 2) = tmp
numberArr.RemoveAt(i)
numberArr.RemoveAt(i - 1)
numberArr = setResultNumberArr(numberArr)
End If
i += 1
End While
Return numberArr
End Function
Private Sub setInputStringArr()
'분리하기
Dim tmp As String = ""
Dim i As Integer
For i = 0 To InputString.Length - 1 Step 1
If Not IsNumeric(InputString(i)) Then
InputStringArr.Add(tmp)
tmp = ""
InputStringArr.Add(InputString(i))
Else
tmp = tmp & InputString(i)
End If
Next i
InputStringArr.Add(tmp)
End Sub
End Class
'프로그래밍 > 비주얼베이직' 카테고리의 다른 글
Dodge : Avoid Balls 비주얼베이직 게임 만들기 공피하기 게임 (0) | 2022.12.22 |
---|