좋아요!
Baekjoon 5639번 이진 검색 트리 문제를 위한 입력 예제, 정답, 코드, 그리고 한 줄 한 줄 디버깅급 풀이를 준비해 드릴게요.
사용자의 요구에 맞춰 예제와 정답을 코드 안에 포함하고, 코드의 각 줄을 예제와 연관 지으며 디버깅하듯 한 줄 한 줄 자세히 해설하겠습니다.
입력: 전위(preorder) 순회 순서가 한 줄에 하나씩 주어지는 이진 검색 트리(BST)가 주어짐.
출력: 후위(postorder) 순회 결과를 한 줄에 하나씩 출력.
50
30
24
5
28
45
98
52
60
5
28
24
45
30
60
52
98
50
이 트리를 그려보면 아래와 같습니다.
50
/ \
30 98
/ \ /
24 45 52
/ \ \
5 28 60
이 트리를 후위 순회(postorder) 하면:
이제 위 트리 구조를 이용하여 동작하는 코드를 짜 보겠습니다.
입력 부분을 코드 안에 포함해서 테스트할 수 있는 형태로 작성하고, 한 줄 한 줄 디버깅 형태의 자세한 설명을 추가하겠습니다.
# 트리의 각 노드를 나타내는 클래스 정의
class Node:
def __init__(self, key):
# 1. 생성자: Node 객체를 만들 때 호출됨
self.key = key # 2. 현재 노드의 값
self.left = None # 3. 왼쪽 자식
self.right = None # 4. 오른쪽 자식
# 트리에 새로운 값을 삽입하는 함수
def insert(root, key):
# 5. 트리의 루트가 비어 있으면 새 Node 반환
if root is None:
return Node(key)
# 6. 삽입할 값이 현재 루트보다 작으면 왼쪽 트리로 재귀 호출
if key < root.key:
root.left = insert(root.left, key)
# 7. 삽입할 값이 현재 루트보다 크면 오른쪽 트리로 재귀 호출
else:
root.right = insert(root.right, key)
# 8. 트리 구조가 바뀐 루트를 반환
return root
# 후위 순회를 출력하는 함수
def postorder(root):
# 9. 현재 노드가 None이면 종료 (리프에서 호출됨)
if root is None:
return
# 10. 왼쪽 서브트리 후위 순회
postorder(root.left)
# 11. 오른쪽 서브트리 후위 순회
postorder(root.right)
# 12. 현재 노드 출력
print(root.key)
# 13. 트리의 루트를 None으로 초기화
root = None
# 14. 여기서 문제의 예제 데이터를 리스트로 준비
preorder_input = [
50,
30,
24,
5,
28,
45,
98,
52,
60
]
# 15. 위 리스트의 각 값을 트리에 삽입
for num in preorder_input:
root = insert(root, num)
# 16. 트리의 후위 순회 호출
postorder(root)
1~4. Node 클래스:
key 속성에 현재 값(노드의 숫자)을 담고, 초기 상태에서는 left와 right를 None(없음) 상태로 둡니다.5~8. insert 함수:
key)을 넣을 때 호출됩니다.root)가 비어 있으면 새로운 노드를 반환해서 트리의 루트를 잡아요.9~12. postorder 함수:
13~16:
preorder_input 리스트 안에 문제의 예제 데이터를 직접 넣었습니다.insert)postorder(root) 호출 -> 트리 출력이 코드를 실행하면 터미널에:
5
28
24
45
30
60
52
98
50
가 출력되며, 우리가 위에서 수작업 계산한 정답과 일치합니다.
맞아요, 질문에서 트리 삽입의 흐름을 잘 이해하고 계신 거 같습니다. 😊
그런데 조금만 다듬으면 훨씬 선명해질 거예요. 한 줄 한 줄 트리 삽입 과정을 정리해 드릴게요.
insert(root, key) 호출def insert(root, key):
if root is None:
return Node(key)
if key < root.key:
root.left = insert(root.left, key)
else:
root.right = insert(root.right, key)
return root
insert(None, 50)root is None)Node(50)을 만들어 반환 → 트리의 루트가 50이 됨.insert(root(50), 30)여기서 root.key == 50, key == 30
root가 None이 아니므로 if문 통과
key(=30) < 50 참 → root.left = insert(root.left, 30)
root.left가 None이므로 insert(None, 30) 호출Node(30) 반환트리 구조:
50
/
30
insert(root(50), 24)이번에도 root.key == 50, key == 24
24 < 50 참 → root.left = insert(root.left(=30), 24)
이제 insert(root(30), 24) 호출
24 < 30 참 → root.left = insert(root.left(None), 24)Node(24) 반환트리 구조:
50
/
30
/
24
insert(root(50), 5)5 < 50 → root.left = insert(30, 5)5 < 30 → root.left = insert(24, 5)5 < 24 → root.left = insert(None, 5) → Node(5) 반환이런 식으로 트리를 아래로 내려가면서 if key < 현재노드.key 검사 후 왼쪽 혹은 오른쪽을 골라 타고 내려갑니다.
✅ 질문 주신 부분 정리
첫 번째 호출: 트리 비어있음 → Node(50) 반환, 트리 루트 = 50두 번째 호출: 트리 루트 = 50 있는데, key=30 → 50보다 작으므로 왼쪽에 삽입따라서 “50이 들어가고, 30이니까 if문에 걸려서 왼쪽에 넣는다” → 맞아요.
단, "넣는다"는 트리의 왼쪽 자식 포인터가Node(30)을 가리키도록 바꾼다는 말이고, 반환값을 반드시root.left = insert(root.left, key)에 대입해주는 부분이 중요합니다.
좋아요! insert가 끝난 상태의 트리 구조를 한눈에 볼 수 있게 정리해 드릴게요.
우리가 넣은 입력 순서는 이거였죠:
50, 30, 24, 5, 28, 45, 98, 52, 60
이 숫자들로 트리를 삽입해 나가면 트리 구조가 어떻게 되는지 한 줄 한 줄 쌓아보겠습니다.
최종 트리 모양:
50
/ \
30 98
/ \ /
24 45 52
/ \ \
5 28 60
50 삽입 → 트리:50
30 삽입 (50 > 30) → 트리:50
/
30
24 삽입 (50 > 24, 30 > 24)50
/
30
/
24
5 삽입 (50 > 5, 30 > 5, 24 > 5)50
/
30
/
24
/
5
28 삽입 (50 > 28, 30 > 28, 24 < 28)50
/
30
/
24
/ \
5 28
45 삽입 (50 > 45, 30 < 45)50
/
30
/ \
24 45
/ \
5 28
98 삽입 (50 < 98)50
/ \
30 98
/ \
24 45
/ \
5 28
52 삽입 (50 < 52, 98 > 52)50
/ \
30 98
/ \ /
24 45 52
/ \
5 28
60 삽입 (50 < 60, 98 > 60, 52 < 60)50
/ \
30 98
/ \ /
24 45 52
/ \ \
5 28 60
✅ 이렇게 트리 삽입이 끝난 상태가 위와 같습니다.
🎯 포스트오더(후위 순회) 할 때의 순서가 위 트리 구조에서 나오는 거예요.
후위 순회(
postorder):
왼쪽 → 오른쪽 → 루트
그래서 출력값이:
5
28
24
45
30
60
52
98
50
맞아요! 후위 순회(postorder)의 핵심은 “왼쪽 → 오른쪽 → 루트” 순서인데,
이 부분을 단계마다 디버깅하면서 트리의 구조와 호출 순서를 보여드릴게요.
최종 트리는 다음과 같습니다:
(50)
/ \
(30) (98)
/ \ /
(24) (45) (52)
/ \
(5) (28) \
(60)
def postorder(root):
if root is None:
return
postorder(root.left) # 1️⃣ 왼쪽
postorder(root.right) # 2️⃣ 오른쪽
print(root.key) # 3️⃣ 루트
후위순회가 어떻게 호출되는지를 “스택” 느낌으로 따라가 볼게요.
postorder(30)postorder(24)postorder(5)5의 왼쪽, 오른쪽은 없음 → 바로 print(5)postorder(28)28도 자식 없음 → print(28)24 출력→ 45 왼쪽/오른쪽 없음 → print(45)
print(30)postorder(98)postorder(52)52의 왼쪽 없음52의 오른쪽 호출: postorder(60) → 60 출력52 출력98 출력print(50)postorder(50)
→ postorder(30)
→ postorder(24)
→ postorder(5) 출력 5
→ postorder(28) 출력 28
출력 24
→ postorder(45) 출력 45
출력 30
→ postorder(98)
→ postorder(52)
→ postorder(60) 출력 60
출력 52
출력 98
출력 50
이 순서대로 출력되는 값:
5
28
24
45
30
60
52
98
50
맞죠? 🎉