백준 1991, 트리 순회 - Tree, Recursive
https://www.acmicpc.net/problem/1991
풀이 ① - 인접 리스트 + 재귀 함수
인접 리스트 List<Character>[] lists
에 트리 저장, 재귀 함수로 트리 순회 구현
1. 아이디어
1) 트리의 노드 연결 정보를 인접 리스트 List<Character>[] lists
에 저장
- 각 노드의 Left Child, Right Child 저장
ex)lists[0]
: 루트 노드 'A'의 Left Child, Right Child 저장
2) 재귀 함수로 각 트리 순회 구현
- 전위 순회 (Preorder): Parent → Left Child → Right Child
- 중위 순회 (Inorder): Left Child → Parent → Right Child
- 후위 순회 (Postorder): Left Child → Right Child → Parent
char[] tree
에 전체 트리(노드들)를 저장하지 않고,
인접 리스트List<Character>[]
를 사용한 이유
- 입력 트리의 형태가 "완전 이진 트리"가 아닌, 그냥 이진 트리
- 트리가 최악으로 Unbalance 할 수 있음
- ex) 최악의 경우로 트리가 오른쪽으로만 길게 뻗친 형태 (Right Child 만 존재)인 경우,
char[] tree
의index
=> 루트[1]
,[3]
,[7]
,[15]
, ...,[2^26 - 1]
- n 최대 노드 개수: 26
- 부모 노드가
[i]
이면, Left Child 는[i * 2]
, Right Child 는[i * 2 + 1]
)
- 메모리 초과 발생
=> 최대char[] tree
의 메모리: (2^26 - 1) x 2 byte = 134,217,726 byte ~= 대략 134 MB >> 128 MB
2. 자료구조
List<Character>[]
,ArrayList<Character>[]
: 각 노드의 Left Child, Right Child 저장
3. 시간 복잡도
-
1개 부모 노드에서 재귀 호출 2번 수행
- 대충 전체 n개 노드에서, 재귀 호출 2번 모두 수행 가정
- 트리 순회 1번 당, O(2 x n)
-
트리 순회 총 3번이므로, 총 시간 복잡도: O(6 x n)
=> n 최대값 대입: 6 x 26 = 156
코드
import java.io.*;
import java.util.*;
public class Main {
static int n; // 이진 트리의 노드 개수
static List<Character>[] lists; // 각 노드의 left, right child 저장
static StringBuilder sb = new StringBuilder(); // 출력 값
static void preorder(char parent) {
List<Character> list = lists[parent - 'A'];
char leftChild = list.get(0);
char rightChild = list.get(1);
// Parent -> Left Child -> Right Child
sb.append(parent);
if (leftChild != '.')
preorder(leftChild);
if (rightChild != '.')
preorder(rightChild);
}
static void inorder(char parent) {
List<Character> list = lists[parent - 'A'];
char leftChild = list.get(0);
char rightChild = list.get(1);
// Left Child -> Parent -> Right Child
if (leftChild != '.')
inorder(leftChild);
sb.append(parent);
if (rightChild != '.')
inorder(rightChild);
}
static void postorder(char parent) {
List<Character> list = lists[parent - 'A'];
char leftChild = list.get(0);
char rightChild = list.get(1);
// Left Child -> Right Child -> Parent
if (leftChild != '.')
postorder(leftChild);
if (rightChild != '.')
postorder(rightChild);
sb.append(parent);
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
StringTokenizer st;
n = Integer.parseInt(br.readLine());
lists = new ArrayList[n]; // [0 ~ n-1]
for (int i = 0; i < n; i++)
lists[i] = new ArrayList<>();
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
char parent = st.nextToken().charAt(0);
char leftChild = st.nextToken().charAt(0);
char rightChild = st.nextToken().charAt(0);
lists[parent - 'A'].add(leftChild);
lists[parent - 'A'].add(rightChild);
}
// 루트 노드 'A' 에서 시작
preorder('A');
sb.append("\n");
inorder('A');
sb.append("\n");
postorder('A');
sb.append("\n");
System.out.println(sb);
}
}
풀이 ② - Tree
직접 구현 + 재귀 함수
Tree
를 직접 구현하여 트리 저장, 재귀 함수로 트리 순회 구현
1. 아이디어
Tree
를 직접 구현
1) 트리 노드 추가
- Left Child 추가
- Right Child 추가
2) 재귀 함수로 각 트리 순회 구현
- 전위 순회 (Preorder): Parent → Left Child → Right Child
- 중위 순회 (Inorder): Left Child → Parent → Right Child
- 후위 순회 (Postorder): Left Child → Right Child → Parent
입력 트리가 이진 트리 형태이고,
입력 노드 연결 정보가 Parent - Left Child - Right Child 의 순서로 주어지므로,
Tree 직접 구현해서 풀이 가능
2. 자료구조
Tree
:Node
들을 갖는 트리 구현 클래스
3. 시간 복잡도
-
1개 부모 노드에서 재귀 호출 2번 수행
- 대충 전체 n개 노드에서, 재귀 호출 2번 모두 수행 가정
- 트리 순회 1번 당, O(2 x n)
-
트리 순회 총 3번이므로, 총 시간 복잡도: O(6 x n)
=> n 최대값 대입: 6 x 26 = 156
코드
import java.io.*;
import java.util.*;
class Node {
public char data;
public Node leftChild;
public Node rightChild;
public Node(char data) {
this.data = data;
}
}
class Tree {
public Node root;
public int size;
public Tree(Node root) {
this.root = root;
size++;
}
/* 트리에서 parentData 값을 갖는 parent 노드를 찾아서,
leftData 값을 갖는 leftChild 노드 추가 */
public void addLeft(char parentData, char leftData) {
if (root == null) {
root = new Node(parentData); // Root 추가
root.leftChild = new Node(leftData); // Left Child 추가
size += 2;
}
else
addLeft(root, parentData, leftData);
}
public void addLeft(Node node, char parentData, char leftData) {
if (node == null) // 못 찾은 경우
return;
else if (node.data == parentData) { // 찾은 경우
node.leftChild = new Node(leftData);
size++;
}
else {
addLeft(node.leftChild, parentData, leftData);
addLeft(node.rightChild, parentData, leftData);
}
}
/* 트리에서 parentData 값을 갖는 parent 노드를 찾아서,
rightData 값을 갖는 rightChild 노드 추가 */
public void addRight(char parentData, char rightData) {
if (root == null) {
root = new Node(parentData); // Root 추가
root.rightChild = new Node(rightData); // Right Child 추가
size += 2;
}
else
addRight(root, parentData, rightData);
}
public void addRight(Node node, char parentData, char rightData) {
if (node == null) // 못 찾은 경우
return;
else if (node.data == parentData) { // 찾은 경우
node.rightChild = new Node(rightData);
size++;
}
else {
addRight(node.leftChild, parentData, rightData);
addRight(node.rightChild, parentData, rightData);
}
}
public StringBuilder sb;
/* 전위 순회: Parent -> Left Child -> Right Child */
public void preorder(Node parent) {
sb.append(parent.data);
if (parent.leftChild != null)
preorder(parent.leftChild);
if (parent.rightChild != null)
preorder(parent.rightChild);
}
/* 중위 순회: Left Child -> Parent -> Right Child */
public void inorder(Node parent) {
if (parent.leftChild != null)
inorder(parent.leftChild);
sb.append(parent.data);
if (parent.rightChild != null)
inorder(parent.rightChild);
}
/* 후위 순회: Left Child -> Right Child -> Parent */
public void postorder(Node parent) {
if (parent.leftChild != null)
postorder(parent.leftChild);
if (parent.rightChild != null)
postorder(parent.rightChild);
sb.append(parent.data);
}
}
public class Main_Tree_Dev {
static int n; // 이진 트리의 노드 개수
static Tree tree;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
StringTokenizer st;
n = Integer.parseInt(br.readLine());
tree = new Tree(new Node('A'));
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
char parentData = st.nextToken().charAt(0);
char leftData = st.nextToken().charAt(0);
char rightData = st.nextToken().charAt(0);
if (leftData != '.')
tree.addLeft(parentData, leftData);
if (rightData != '.')
tree.addRight(parentData, rightData);
}
tree.sb = new StringBuilder();
tree.preorder(tree.root);
tree.sb.append("\n");
tree.inorder(tree.root);
tree.sb.append("\n");
tree.postorder(tree.root);
tree.sb.append("\n");
System.out.println(tree.sb);
}
}
Author And Source
이 문제에 관하여(백준 1991, 트리 순회 - Tree, Recursive), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@silver_star/백준-1991-트리-순회-Tree-Recursive저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)