트리에 대해 알아보자! 🌳
트리(Tree)란? 🤔
트리는 계층적인 구조를 가진 자료구조입니다. 루트(root) 노드에서 시작해 여러 개의 자식 노드를 가지며, 각각의 자식 노드도 다시 서브 트리를 형성합니다. 트리는 그래프의 한 종류로, 사이클이 없는 방향성 비순환 그래프(DAG)입니다.
트리의 기본 개념 🌟
노드(Node): 트리의 기본 요소로, 데이터와 자식 노드에 대한 참조를 가집니다. 루트 노드(Root Node): 트리의 최상위 노드입니다. 리프 노드(Leaf Node): 자식 노드가 없는 노드입니다. 간선(Edge): 노드 간의 연결을 나타냅니다. 서브 트리(Subtree): 트리의 부분 집합으로, 특정 노드와 그 노드의 모든 자식 노드를 포함합니다.
트리의 종류 🌳
이진 트리(Binary Tree): 모든 노드가 두 개 이하의 자식을 가지는 트리입니다. 이진 탐색 트리(BST, Binary Search Tree): 이진 트리의 일종으로, 왼쪽 자식은 부모보다 작고, 오른쪽 자식은 부모보다 큰 값을 가집니다. 균형 이진 트리(Balanced Binary Tree): 모든 리프 노드의 높이가 거의 같은 이진 트리입니다. 힙(Heap): 완전 이진 트리의 일종으로, 부모 노드가 자식 노드보다 크거나(최대 힙) 작은(최소 힙) 특성을 가집니다.
트리의 장단점 🎢
장점 계층적 데이터 표현: 데이터의 계층 구조를 표현하기에 적합합니다. 빠른 탐색: 이진 탐색 트리와 같이 탐색에 최적화된 구조를 가질 수 있습니다. 단점 복잡한 구현: 트리의 삽입, 삭제, 탐색 등의 연산이 비교적 복잡합니다. 불균형 문제: 트리가 불균형해지면 성능이 저하될 수 있습니다.
파이썬에서 트리 구현 💻
파이썬에서는 클래스를 사용해 트리를 구현할 수 있습니다.
1class Node:2 def __init__(self, key):3 self.left = None4 self.right = None5 self.val = key6
7# 이진 트리 예제8root = Node(1)9root.left = Node(2)10root.right = Node(3)11root.left.left = Node(4)12root.left.right = Node(5)13
14print(root.val) # 출력: 115print(root.left.val) # 출력: 2프로그래머스 트리 문제 🚀
문제: 길 찾기 게임 🗺️ 문제 설명 이진 트리에서 노드의 좌표를 기반으로 주어진 노드들을 삽입하여 트리를 구성하고, 전위(preorder) 순회와 후위(postorder) 순회의 결과를 반환하는 문제입니다.
입력 예시 nodeinfo = [[5, 3], [11, 5], [13, 3], [3, 5], [6, 1], [1, 3], [8, 6], [7, 2], [2, 2]] 출력 예시 [[7, 4, 6, 9, 1, 8, 5, 2, 3], [5, 1, 8, 9, 6, 4, 2, 3, 7]]
코드 작성하기 💻
1import sys2sys.setrecursionlimit(10**6)3
4class Node:5 def __init__(self, key, x, y):6 self.key = key7 self.x = x8 self.y = y9 self.left = None10 self.right = None11
12def insert_node(root, node):13 if node.x < root.x:14 if root.left is None:15 root.left = node16 else:17 insert_node(root.left, node)18 else:19 if root.right is None:20 root.right = node21 else:22 insert_node(root.right, node)23
24def preorder(node, traversal):25 if node:26 traversal.append(node.key)27 preorder(node.left, traversal)28 preorder(node.right, traversal)29
30def postorder(node, traversal):31 if node:32 postorder(node.left, traversal)33 postorder(node.right, traversal)34 traversal.append(node.key)35
36def solution(nodeinfo):37 nodes = sorted([(i + 1, x, y) for i, (x, y) in enumerate(nodeinfo)], key=lambda x: (-x[2], x[1]))38 root = Node(*nodes[0])39 for node in nodes[1:]:40 insert_node(root, Node(*node))41
42 preorder_traversal = []43 postorder_traversal = []44
45 preorder(root, preorder_traversal)46 postorder(root, postorder_traversal)47
48 return [preorder_traversal, postorder_traversal]49
50# 테스트51nodeinfo = [[5, 3], [11, 5], [13, 3], [3, 5], [6, 1], [1, 3], [8, 6], [7, 2], [2, 2]]52print(solution(nodeinfo)) # 출력: [[7, 4, 6, 9, 1, 8, 5, 2, 3], [5, 1, 8, 9, 6, 4, 2, 3, 7]]설명 📋
노드를 y좌표 기준으로 내림차순, x좌표 기준으로 오름차순 정렬합니다. 정렬된 순서대로 트리를 구성합니다. 전위 순회와 후위 순회를 수행하여 결과를 반환합니다.
팁 🌟
재귀 사용: 트리의 탐색이나 순회에는 재귀 함수를 많이 사용합니다. 정렬 기준 이해: 문제의 요구사항에 맞게 정렬 기준을 설정하는 것이 중요합니다. 트리의 특성 이해: 트리의 기본적인 특성과 트리 순회의 방법(전위, 중위, 후위)을 이해하고 있으면 문제 해결에 큰 도움이 됩니다.