본 시리즈는 프로그래밍 자료구조의 개념을 정리하고 실습을 진행해보는 시리즈입니다.
트리(Tree)는 계층적인 구조를 표현하는 비선형 자료구조입니다.
계층적 구조: 트리는 루트 노드(최상단 노드)에서 시작해 자식 노드(아래 방향)들로 뻗어 나가는 계층적 자료구조로, 데이터를 논리적이고 구조화된 방식으로 표현할 수 있습니다.
루트 노드(Root Node): 트리의 최상단 노드로, 트리의 시작점이 됩니다.
부모-자식 관계: 트리에서 각 노드는 부모(Parent) 노드와 자식(Child) 노드의 관계를 형성합니다.
리프 노드(Leaf Node): 자식 노드가 없는 노드를 리프 노드라고 부르며, 트리의 말단을 의미합니다.
비순환성(Acyclic): 트리는 사이클(순환)이 없는 비순환 구조입니다.
연결성(Connectedness): 트리의 모든 노드는 루트 노드에서 단 하나의 경로로 연결됩니다.
트리는 이러한 특징들 덕분에 디렉토리 구조, 데이터베이스 인덱스 등 계층적인 데이터 관리와 탐색에 널리 사용됩니다.
트리는 다양한 분야에서 데이터의 계층적 구조를 표현하는 데 유용하며, 특히 다음과 같은 주요 용도로 사용됩니다.
파일 시스템 구조: 트리는 디렉토리 구조와 파일 시스템을 표현하는 데 사용됩니다.
데이터베이스 인덱스: 트리는 데이터베이스 인덱싱에서 효율적인 검색을 위해 사용됩니다.
컴파일러 구조: 트리는 컴파일러가 구문 분석 시 프로그램의 구조를 나타낼 때 사용됩니다.
이진 탐색 트리(Binary Search Tree, BST): 이진 트리는 검색 속도를 개선하기 위해 활용됩니다.
네트워크 라우팅: 트리는 네트워크에서 효율적인 경로 탐색 및 패킷 전달을 위해 사용되며, 최소 신장 트리(MST) 같은 알고리즘으로 네트워크 연결을 최적화할 수 있습니다.
게임 및 AI: 트리는 게임 트리, 의사결정 트리(Decision Tree) 등의 구조로 활용되며, AI와 머신러닝 분야에서는 의사결정 트리(Decision Tree)와 같은 알고리즘이 사용됩니다.
트리는 그 특유의 계층성 덕분에 데이터의 구조화, 탐색, 최적화 등 다양한 문제를 해결하는 데 중요한 역할을 합니다.
트리는 그래프의 특수한 형태로, 두 자료구조는 기본적으로 비슷한 점이 있지만 몇 가지 차이점이 있습니다.
비교 항목 | Tree | Graph |
---|---|---|
구조 | 계층적 구조 (루트에서 자식 노드로 이어짐) | 일반적인 네트워크 구조 (정점 간의 다양한 연결 가능) |
루트 노드 | 단 하나의 루트 노드가 존재 | 특정 루트 노드가 없음 (모든 노드가 동등) |
부모-자식 관계 | 노드 간 명확한 부모-자식 관계 존재 | 부모-자식 관계 없이 노드 간 자유로운 연결 |
순환성 | 비순환성 (사이클이 없음) | 사이클이 존재할 수 있음 |
연결성 | 루트 노드에서 단일 경로로 모든 노드가 연결됨 | 모든 노드가 여러 경로로 연결될 수 있음 |
용도 | 파일 시스템, 데이터베이스 인덱스 등 계층적인 데이터 표현 | 네트워크 모델링, 소셜 네트워크, 지도 등 다양한 분야에서 사용 |
Tree는 Graph의 특수한 형태로, 사이클이 없고 명확한 부모-자식 관계를 가진 계층적 구조입니다.
이러한 차이 덕분에 트리는 계층적 데이터를 표현하거나 탐색하는 데 적합한 자료구조이고, 그래프는 복잡한 네트워크나 연결성을 분석하는 데 적합한 자료구조입니다.
트리의 기본적인 구조와 용어를 이해하는 것은 트리 자료구조를 효과적으로 활용하는 데 매우 중요합니다.
여기에서는 트리에서 자주 사용되는 용어들을 정리합니다.
1
만큼 큽니다.1
만큼 큽니다.이번 섹션에서는 트리(Tree) 자료구조를 Java와 Python에서 어떻게 구현할 수 있는지 다루어 보겠습니다.
Java에서는 클래스 기반으로 트리를 구현하며, 노드 클래스(Node)와 트리 클래스(Tree)를 따로 만들어 트리 구조를 정의합니다.
먼저, 트리의 기본 단위인 노드를 정의합니다.
import java.util.ArrayList;
import java.util.List;
class Node {
String data;
List<Node> children;
// 노드 생성자
public Node(String data) {
this.data = data;
this.children = new ArrayList<>();
}
// 자식 노드 추가
public void addChild(Node child) {
this.children.add(child);
}
}
트리의 루트를 관리하고, 트리 전체를 탐색하는 기능을 포함하는 트리 클래스를 정의합니다.
class Tree {
Node root;
// 트리 생성자 (루트 노드를 설정)
public Tree(String rootData) {
root = new Node(rootData);
}
// 전위 순회 (Pre-order Traversal)
public void traversePreOrder(Node node) {
if (node != null) {
System.out.print(node.data + " ");
for (Node child : node.children) {
traversePreOrder(child);
}
}
}
}
부모노드 -> 왼쪽 ~ 오른쪽 자식노드
순서로 트리를 재귀적으로 순회하는 알고리즘인데, 주로 트리 차수가 2인 이진트리에서 자주 사용하는 알고리즘입니다. 이제 트리를 생성하고 탐색을 수행해보겠습니다.
public class Main {
public static void main(String[] args) {
// 트리 생성
Tree tree = new Tree("Root");
Node child1 = new Node("Child1");
Node child2 = new Node("Child2");
tree.root.addChild(child1);
tree.root.addChild(child2);
Node grandChild1 = new Node("GrandChild1");
Node grandChild2 = new Node("GrandChild2");
child1.addChild(grandChild1);
child2.addChild(grandChild2);
// 전위 순회
System.out.println("Pre-order Traversal:");
tree.traversePreOrder(tree.root); // 출력: Root Child1 GrandChild1 Child2 GrandChild2
}
}
위 코드에서 전위 순회(Pre-order Traversal)를 수행하면, 트리의 루트 노드부터 시작하여 자식 노드들을 왼쪽에서 오른쪽으로 차례로 탐색합니다.
Python에서도 트리를 클래스 기반으로 구현합니다.
Python에서 노드를 정의하는 방법은 매우 간단합니다.
class Node:
def __init__(self, data):
self.data = data
self.children = []
# 자식 노드 추가
def add_child(self, child):
self.children.append(child)
이제 트리 클래스를 정의하여 트리 전체를 관리하고 탐색 기능을 구현합니다.
class Tree:
def __init__(self, root_data):
self.root = Node(root_data)
# 전위 순회 (Pre-order Traversal)
def traverse_preorder(self, node):
if node:
print(node.data, end=' ')
for child in node.children:
self.traverse_preorder(child)
Python에서도 트리를 생성하고 탐색을 수행해보겠습니다.
# 트리 생성
tree = Tree("Root")
child1 = Node("Child1")
child2 = Node("Child2")
tree.root.add_child(child1)
tree.root.add_child(child2)
grandchild1 = Node("GrandChild1")
grandchild2 = Node("GrandChild2")
child1.add_child(grandchild1)
child2.add_child(grandchild2)
# 전위 순회
print("Pre-order Traversal:")
tree.traverse_preorder(tree.root) # 출력: Root Child1 GrandChild1 Child2 GrandChild2
Python에서는 print()
문을 사용하여 각 노드를 출력하고, 전위 순회(Pre-order Traversal) 방식으로 트리의 모든 노드를 탐색합니다.
트리 자료구조는 탐색 알고리즘에서 중요한 역할을 하며, 대표적인 트리 순회(Traversal) 방법에는 다음 세 가지가 있습니다.
위 예시에서는 전위 순회만을 다뤘지만, 필요에 따라 중위나 후위 순회 방식도 추가적으로 구현할 수 있습니다.
이번 포스팅에서는 트리 자료구조의 기본 개념과 구현 방법에 대해 살펴보았습니다.
트리는 파일 시스템, 데이터베이스 인덱스, 게임 개발 등 다양한 분야에서 활용되며, 데이터를 계층적으로 표현하는 데 매우 유용한 자료구조입니다.
다음 포스팅에서는 트리의 특수한 형태인 이진 트리(Binary Tree)를 다루며, 다양한 탐색 알고리즘과 활용 사례들을 알아보겠습니다.