트리 Tree는 데이터 구조 중 하나로, 계층적
으로 구성된 노드들의 집합을 나타낸다. 트리는 하나의 루트 노드(root node)에서 시작해서 여러 개의 자식 노드(child node)를 가지며, 자식 노드들도 각각 다시 자신의 자식 노드들을 가질 수 있다.
트리는 데이터를 계층적
으로 구성하고 관리하는 데 매우 유용한 자료구조이다.
예를 들어, 조직도, 가계도 및 파일 시스템에서 폴더 구조(디렉터리)와 파일들의 관계
를 나타내는 데 사용되고, 알고리즘에서도 널리 활용되는데 대표적인 예로는 이진 탐색(Binary Search)
이 있다.
Sub-Tree
로 분리됨이진 트리(binary tree)는 각 노드가 최대 두 개의 자식 노드를 가지는 트리 구조이다.
자식 노드는 왼쪽 자식과 오른쪽 자식을 구분한다. (순서 트리)
아래 두 트리는 서로 다른 트리이다.
이진 트리는 매우 중요한 자료 구조 중 하나이며, 다양한 알고리즘에서 사용된다. 이진 탐색 트리(binary search tree)는 이진 트리의 일종으로, 특히 검색과 삽입 연산에서 매우 효율적인 구현이 가능하다.
이진 트리
는 매우 다양한 변형이 있으며, 이진 탐색 트리 외에도 AVL 트리, 레드-블랙 트리, B-트리 등 많은 유형이 있습니다. 각각의 트리는 다른 목적을 가지고 있으며, 특정한 알고리즘에서 더욱 효율적인 구현을 가능하게 합니다.
전위순회 (Pre-order Traversal)
전위순회는 트리의 구조를 파악하기 위해 사용될 수 있고, 트리의 노드를 복사하거나 클론하는 경우
에 유용하다.
중위순회 (In-order Traversal)
중위순회는 정렬된 값을 출력
하거나, 특정한 노드를 찾는 등의 작업
에 사용될 수 있다.
후위순회 (Post-order Traversal)
후위순회는 트리의 리프 노드에서 시작해서 루트 노드로 탐색하는 것과 같은 방법으로 사용될 수 있고,
후위순회를 이용하면 트리의 노드를 삭제하는 경우에 유용
합니다.
레벨순회 (Level-order Traversal)
트리의 레벨별로 작업
을 수행해야 할 때 사용된다.
방문순서 : 현재 노드 ▶ 왼쪽 노드 ▶ 오른쪽 노드
방문순서 : 왼쪽 노드 ▶ 현재 노드 ▶ 오른쪽 노드
방문순서 : 왼쪽 노드 ▶ 오른쪽 노드 ▶ 현재 노드
방문순서 : 위쪽 레벨부터 왼쪽 노드 ▶ 오른쪽 노드
이진 트리를 구현하는 방법에는 두 가지가 있다.
하나는 배열(array)을 사용하는 방법이며, 다른 하나는 연결 리스트(linked list)를 사용하는 방법이다.
백준 - 트리의 부모 찾기
import java.util.*;
public class Main {
static int N;
static ArrayList<Integer>[] adj;
static int[] parent;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
// 인접 리스트 생성
adj = new ArrayList[N + 1];
for (int i = 1; i <= N; i++) {
adj[i] = new ArrayList<>();
}
// 노드 연결 정보 입력
for (int i = 0; i < N - 1; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
// 무향 그래프이므로 양방향으로 연결
adj[u].add(v);
adj[v].add(u);
}
parent = new int[N + 1];
dfs(1, 0);
// 루트 노드를 제외하고 각 노드의 부모 노드 출력
for (int i = 2; i <= N; i++) {
System.out.println(parent[i]);
}
sc.close();
}
// DFS를 이용하여 각 노드의 부모 노드를 찾는 함수
private static void dfs(int cur, int prev) {
parent[cur] = prev;
for (int next : adj[cur]) {
if (next != prev) {
dfs(next, cur);
}
}
}
}
위의 코드에서는 인접 리스트를 이용하여 트리를 구성하고, DFS(Depth-First Search) 알고리즘을 이용하여 각 노드의 부모 노드를 찾는다.
먼저, N 변수에 노드의 개수를 입력받고, adj 변수에는 인접 리스트를 생성한다. 이후, 입력받은 노드 연결 정보를 이용하여 무향 그래프를 생성하고, 무향 그래프이므로 각 연결 정보에 대해 양방향으로 연결한다.
그 다음으로는 parent 배열을 초기화하고, DFS를 이용하여 각 노드의 부모 노드를 찾는다.
DFS 함수에서는 현재 노드의 부모 노드를 저장하고, 자식 노드를 탐색한다.
자식 노드는 부모 노드와 연결된 노드이며, 이미 방문한 노드인 경우에는 탐색하지 않는다.
마지막으로는 루트 노드를 제외하고, 각 노드의 부모 노드를 출력한다.
백준 - 이진 검색 트리 (5639)
import java.util.Scanner;
class Node {
int data;
Node left;
Node right;
public Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
public class Main {
static Node root = null;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int data = sc.nextInt();
root = new Node(data);
while (sc.hasNext()) {
data = sc.nextInt();
insert(root, data);
}
postorder(root);
}
// 이진검색트리에 노드를 삽입하는 함수
private static void insert(Node node, int data) {
if (data < node.data) {
if (node.left == null) {
node.left = new Node(data);
} else {
insert(node.left, data);
}
} else {
if (node.right == null) {
node.right = new Node(data);
} else {
insert(node.right, data);
}
}
}
// 후위순회(postorder) : 왼쪽 자식 -> 오른쪽 자식 -> 루트
private static void postorder(Node node) {
if (node == null) {
return;
}
postorder(node.left);
postorder(node.right);
System.out.println(node.data);
}
}
위의 코드에서는 Node 클래스를 정의하여 이진트리를 구현한다. 이진검색트리에 노드를 삽입하는 insert 함수와 후위순회를 수행하는 함수 postorder를 구현하였다. 이진검색트리의 루트 노드를 root 변수에 저장하고, 전위순회 결과를 입력으로 받아서 이진검색트리를 생성한다. 이진검색트리에서는 노드를 삽입할 때, 현재 노드보다 작은 값은 왼쪽 자식 노드에, 큰 값은 오른쪽 자식 노드에 삽입한다. 이렇게 생성된 이진검색트리를 후위순회한 결과를 출력한다.