04-1 트리란?
04-2 이진 트리
04-3 이진 트리의 연산
04-4 모스 코드 결정 트리
04-5 수식 트리

N-링크 표현
왼쪽 자식-오른쪽 형제 표현
Quiz
- (a) A
(b) D
(c) H, I
(d) 3
(e) 4
(f) 3- (a)
(b) (A (B (E)(F)) (C (G)(H)(I)) (D (J (K)(L)))
포화 이진 트리
완전 이진 트리
균형 이진 트리
경사 이진 트리
배열 구조 표현
(1) 트리의 높이를 구해 배열(또는 파이썬의 리스트)을 할당함
- 높이가 이면 길이가 인 배열이 필요함
(2) 포화 이진 트리의 번호를 인덱스로 사용해 배열에 노드들을 저장함
- 노드 i의 부모 노드 인덱스 = i/2
- 노드 i의 왼쪽 자식 노드 인덱스 = 2i
- 노드 i의 오른쪽 자식 노드 인덱스 = 2i + 1
연결된 구조 표현: 링크 표현법
class BTNode:
def __init__(self, elem, left=None, right=None):
self.data = elem
self.left = left
self.right = right
Quiz
- 9
- 31
- 16, 31
- 6
전위 순회
def preorder(n):
if n is not None:
print(n.data, end=' ')
preorder(n.left)
preorder(n.right)
중위 순회
def inorder(n):
if n is not None:
inorder(n.left)
print(n.data, end=' ')
inorder(n.right)
후위 순회
def postorder(n):
if n is not None:
postorder(n.left)
postorder(n.right)
print(n.data, end=' ')
순회 방법의 선택
def levelorder(root):
queue = ArrayQueue()
queue.enqueue(root)
while not queue.isEmpty():
n = queue.dequeue()
if n is not None:
print(n.data, end=' ')
queue.enqueue(n.left)
queue.enqueue(n.right)
전체 노드의 수 구하기

def count_node(n):
if n is None:
return 0
else:
return count_node(n.left) + count_node(n.right) + 1
트리의 높이 구하기

def clac_height(n):
if n is None:
return 0
hLeft = clac_height(n.left)
hRight = clac_height(n.right)
if (hLeft > hRight):
return hLeft + 1
else: return hRight + 1
d = BTNode('D', None, None)
e = BTNode('E', None, None)
b = BTNode('B', d, e)
f = BTNode('F', None, None)
c = BTNode('C', f, None)
root = BTNode('A', b, c)
print('\n In-Order : ', end=' '); inorder(root)
print('\n Pre-Order : ', end=' '); preorder(root)
print('\n Post-Order : ', end=' '); postorder(root)
print('\n Level-0rder : ', end=' '); levelorder(root)
print()
print(" 노드의 개수 = %d 개" % count_node(root))
print(" 트리의 높이 = %d" % calc_height(root))
In-Order : D B E A F C
Pre-Order : ( A ( B (D) (E) ) ( C (F) ) )
Post-Order : D E B F C A
Level-0rder : A B C D E F
노드의 개수 = 6개
트리의 높이 = 3
Quiz
- (전위) 24 19 15 11 17 23 20 42 41 28 55
(중위) 11 15 17 19 20 23 24 28 41 42 55
(하위) 11 17 15 20 23 19 28 41 55 42 24def preorder(n): if n is not None: print("(", end='') print(n.data, end=' ') print(")", end='') preorder(n.left) preorder(n.right)

문자를 모스 코드로 변환하는 과정: 인코딩

def encode(ch):
idx = ord(ch)-ord('A')
return table[idx][1]
모스 코드를 문자로 변환하는 과정: 디코딩(decoding)
def decode_simple(morse):
for tp in table:
if morse == tp[1]:
return tp[0]
표의 크기가 n개라면 n번 비교해야함 -> 비효율적

모스 코드 결정 트리 만들기
(1) 빈 루트 노드를 만들고 모스 코드표의 각 문자를 하나씩 트리에 추가함
(2) 문자를 추가할 때 루트부터 시작해 트리를 타고 내려감, 만약 타고 내려갈 자식 노드라 None이면 새로운 노드를 추가함, 노드만 추가할 뿐이고 그 노드의 문자는 결정할 수 없음
(3) 마지막 코드의 노드에 도달하면 그 노드에 문자를 할당함
def make_morse_tree()
root = BTNode(None, None, None)
for tp in table:
code = tp[1]
node = root
for c in code:
if c == '`':
if node.left == None:
node.left = BTnode(None, None, None)
node = node.left
elif c == '-':
if node.right == None:
node.right = BTNode(None, None, None)
node = node.right
node.data = tp[0]
return root
결정 트리를 이용한 디코딩
def decode(root, code):
node = root
for c in code:
if c == '`': node = node.left
elif c == '-': node = node.right
return node.data
n개의 노드를 갖는 포화 이진 트리라면, 에 비례하는 비교 필요
테스트 프로그램
morseCodeTree = make_morse_tree()
str = input("입력 문장 : ")
mlist = []
for ch i n str:
code = encode(ch)
mlist.append(code)
print("Morse Code: ", mlist)
print("Decodi ng : ", end=")
for code in mlist:
ch = decode(morseCodeTree, code)
print(ch, end=' ')
print()
입력 문장 : GAMEOVER
Morse Code: ['--.', '.-'. '--', '.', '---', '...-', '.', '.-.']
Decoding : GAMEOVER
Quiz
- -.. .- - .-
- TREE
- MEE

def evaluate(node):
if node is None:
return 0
elif node.isLeaf():
return node.data
else:
op1 = evaluate(node.left)
op2 = evaluate(node.right)
if node.data == '+': return op1 + op2
elif node.data == '-': return op1 - op2
elif node.data == '*': return op1 * op2
elif node.data == '/': return op1 / op2

전위표기 식으로 수식 트리 만들기
입력 수식: * + 1 3 / 4 2* 첫 항목*은 수식 트리의 루트 노드가 됨+ 이전 항목*이 연산자이므로 +는 *의 왼쪽 자식이 됨1 이전 항목+이 다시 연산자이므로 1은 +의 왼쪽 자식이 됨3 이전 항목1이 피연산자이므로 3은 이전 연산자+의 두 번째 피연산자가 됨, 두 번째 피연산자가 처리되었으므로 +을 루트로 하는 서브 트리는 완성됨/ 이제 /는 이전 연산자 *의 오른쪽 자식이 됨4 이전 연산자의 왼쪽 자식이 됨2 이전 연산자의 오른쪽 자식이 됨후위표기 식으로 수식 트리 만들기
입력 수식: 1 3 + 4 2 / ** 끝 항목*은 수식 트리의 루트 노드가 됨/ 이전 항목*이 연산자이므로 /는 *의 오른쪽 자식이 됨2 이전 항목/이 다시 연산자이므로 2은 +의 왼쪽 자식이 됨4 이전 항목2이 피연산자이므로 4은 이전 연산자/의 첫 번째 피연산자가 됨, 피 연산자들이 모두 처리되었으므로 /를 루트로 하는 서브 트리는 완성됨+ 이제 +는 이전 연산자 *의 왼쪽 자식이 됨3 이전 연산자의 오른쪽 자식이 됨1 이전 연산자의 왼쪽 자식이 됨def buildETree(expr):
if len(expr) == 0:
return None
token = expr.pop()
if token in "+-*/"
node = BTNode(token)
node.right= buildETree(expr)
node.left = buildETree(expr)
return node
else:
return BTNode(float(token))
테스트 프로그램
str = input("입력(후위표기): ")
expr = str.split()
print("토큰분리 (expr): ", expr)
root = buildETree(expr)
print('\n 전위순회: ', end=''); preorder(root)
print('\n 중위순회: ' , end=''); inorder(root)
print('\n 후위순회: ', end=''); postorder(root)
print('\n 계산 결과 : ', evaluate(root))
입력(후위표기) : 1 3 + 4 2 / *
토큰분리(expr) : ['1', '3', '+', '4', '2', '/', '*']
전위 순회: ( * ( + ( 1.0 ) ( 3.0 ) ) ( / ( 4.0 ) ( 2.0 ) ) )
중위 순회: 1.0 + 3.0 * 4.0 / 2.0
후뤼 순회: 1.0 3.0 + 4.0 2.0 / *
계산 결과: 8.0
Quiz
2 + 8 4/
1 3- 6
class NodeNLink:
def __init__(self, value):
self.value = value
self.links = [] # 연결 리스트를 이용한 링크 저장
def add_link(self, node):
self.links.append(node)
class NodeLeftChildRightSibling:
def __init__(self, value):
self.value = value
self.left_child = None
self.right_sibling = None
def count_leaf_nodes(root):
if not root:
return 0
if not root.left and not root.right:
return 1
return count_leaf_nodes(root.left) + count_leaf_nodes(root.right)
MORSE_CODE_DICT = {
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', 'I': '..',
'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--', 'Z': '--..',
'1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', '0': '-----',
'.': '.-.-.-', ',': '--..--', '?': '..--..', '/': '-..-.', '-': '-....-', '(': '-.--.', ')': '-.--.-'
}
REVERSE_MORSE_CODE_DICT = {v: k for k, v in MORSE_CODE_DICT.items()}
def encode_morse(text):
return ' '.join(MORSE_CODE_DICT.get(char.upper(), '') for char in text)
def decode_morse(morse_code):
return ''.join(REVERSE_MORSE_CODE_DICT.get(code, '') for code in morse_code.split(' '))
def precedence(op):
"""연산자의 우선순위를 반환"""
if op in ('+', '-'):
return 1
if op in ('*', '/'):
return 2
if op == '^': # 거듭제곱
return 3
return 0
def infix_to_postfix(expression):
"""중위표기식을 후위표기식으로 변환"""
output = []
stack = []
for token in expression.split():
if token.isnumeric(): # 숫자는 바로 출력
output.append(token)
elif token == '(': # 왼쪽 괄호는 스택에 push
stack.append(token)
elif token == ')': # 오른쪽 괄호는 '(' 만날 때까지 pop
while stack and stack[-1] != '(':
output.append(stack.pop())
stack.pop() # '(' 제거
else: # 연산자
while stack and precedence(stack[-1]) >= precedence(token):
output.append(stack.pop())
stack.append(token)
# 스택에 남아있는 연산자 출력
while stack:
output.append(stack.pop())
return ' '.join(output)
# 테스트
expr = "3 + 5 * ( 2 - 8 )"
print(infix_to_postfix(expr)) # 출력: 3 5 2 8 - * +