// Practice1
// 배열을 이용한 이진 트리 구성, 순회
class BinaryTree {
char[] arr;
BinaryTree(char[] data) {
this.arr = data.clone();
}
// 받아온 데이터를 클론해주는 형태
public void preOrder(int idx) {
System.out.print(this.arr[idx] + " ");
// 처음에 들어온 인덱스에 해당하는 데이터 출력 (현재)
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < this.arr.length) { // 왼쪽의 인덱스가 배열 범위 안에 들어 있으면 (왼쪽)
this.preOrder(left); // 재귀 함수 형태로 (왼쪽이 출력)
}
if (right < this.arr.length) { // 오른쪽 인덱스가 뱌열 범위 안에 들어 있으면 (오른쪽)
this.preOrder(right); // 재귀 함수 형태로 (오른쪽이 출력)
}
}
public void inOrder(int idx) {
int left = 2 * idx + 1; // 왼쪽 자식 인덱스
int right = 2 * idx + 2; // 오른쪽 자식 인덱스
if (left < this.arr.length) {
this.inOrder(left); // 왼쪽으로 먼저 쭉 내려간 다음 (재귀)
}
System.out.print(this.arr[idx] + " "); // 현재 출력
if (right < this.arr.length) {
this.inOrder(right); // 오른쪽으로 쭉 내려감 (재귀)
}
}
public void postOrder(int idx) {
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < this.arr.length) {
this.postOrder(left); // 왼쪽으로 먼저 쭉 내려간 다음 (재귀)
}
if (right < this.arr.length) {
this.postOrder(right); // 오른쪽으로 쭉 내려감 (재귀)
}
System.out.print(this.arr[idx] + " "); // 현재 출력
}
public void levelOrder(int idx) {
for (int i = idx; i < this.arr.length; i++) {
System.out.print(this.arr[i] + " ");
}
System.out.println();
}
}
public class Practice1 {
public static void main(String[] args) {
// Test code
char[] arr = new char[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (char)('A' + i);
}
BinaryTree bt = new BinaryTree(arr);
System.out.println("== Preorder ==");
bt.preOrder(0);
System.out.println();
System.out.println("== Inorder ==");
bt.inOrder(0);
System.out.println();
System.out.println("== Postorder ==");
bt.postOrder(0);
System.out.println();
System.out.println("== Levelorder ==");
bt.levelOrder(0);
System.out.println();
}
}
<실행 결과>
== Preorder ==
A B D H I E J C F G
== Inorder ==
H D I B J E A F C G
== Postorder ==
H I D J E B F G C A
== Levelorder ==
A B C D E F G H I J
// Practice2
// 연결 리스트를 이용한 이진 트리 구성, 순회
import java.util.LinkedList;
import java.util.Queue;
class Node {
char data;
Node left;
Node right;
Node(char data, Node left, Node right) {
this.data = data;
this.left = left;
this.right = right;
}
}
class BinaryTree2 {
Node head;
BinaryTree2() {}
BinaryTree2(char[] arr) { // 연결 작업 하는 부분 (기본 트리 구조)
Node[] nodes = new Node[arr.length]; // char[] arr 배열을 노드 형태의 배열로 만들어 준다.
for (int i = 0; i < arr.length; i++) {
nodes[i] = new Node(arr[i], null, null);
}
for (int i = 0; i < arr.length; i++) { // 현재 노드에 대해서 자식 노드들을 찾아준다.
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < arr.length) { // 왼쪽 범위 체크
nodes[i].left = nodes[left]; // 노드 연결
}
if (right < arr.length) { // 오른쪽 범위 체크
nodes[i].right = nodes[right]; // 노드 연결
}
}
this.head = nodes[0]; // 루트 노드에 대한 연결 부분
}
public void preOrder(Node node) { // 전위 순회
if (node == null) { // 노드가 비어 있으면 (재귀함수 탈출 조건)
return;
}
System.out.print(node.data + " "); // 현재
preOrder(node.left); // 왼쪽
preOrder(node.right); // 오른쪽
}
public void inOrder(Node node) { // 중위 순회
if (node == null) { // 노드가 비어 있으면 (재귀함수 탈출 조건)
return;
}
inOrder(node.left); // 왼쪽
System.out.print(node.data + " "); // 현재
inOrder(node.right); // 오른쪽
}
public void postOrder(Node node) { // 후위 순회
if (node == null) { // 노드가 비어 있으면 (재귀함수 탈출 조건)
return;
}
postOrder(node.left); // 왼쪽
postOrder(node.right); // 오른쪽
System.out.print(node.data + " "); // 현재
}
public void levelOrder(Node node) { // 레벨 순회 (재귀 함수로 이용하면 오히려 불편이요)
// 큐에다 A 넣고 pop하고 링크 검사(B와 C), B pop하고 링크 검사(D와 E), C pop하고 링크 검사(F와 G) D pop 하고 링크 검사 (없음) ...
Queue<Node> queue = new LinkedList<>(); // 큐 이용!
queue.add(node); // 현재 노드부터 추가
while (!queue.isEmpty()) { // 큐가 비어 있지 않는 동안 순회
Node cur = queue.poll(); // 큐에서 하나 꺼냄
System.out.print(cur.data + " "); // 출력
if (cur.left != null) { // 링크 검사
queue.offer(cur.left); // 자식 노드가 있으면 큐에다가 다시 넣어줌
}
if (cur.right != null) { // 링크 검사
queue.offer(cur.right); // 자식 노드가 있으면 큐에다가 다시 넣어줌
}
}
}
}
public class Practice2 {
public static void main(String[] args) {
// Test code
char[] arr = new char[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (char)('A' + i);
}
BinaryTree2 bt = new BinaryTree2(arr);
System.out.println("== Preorder ==");
bt.preOrder(bt.head);
System.out.println();
System.out.println("== Inorder ==");
bt.inOrder(bt.head);
System.out.println();
System.out.println("== Postorder ==");
bt.postOrder(bt.head);
System.out.println();
System.out.println("== Levelorder ==");
bt.levelOrder(bt.head);
System.out.println();
}
}
<실행 결과>
== Preorder ==
A B D H I E J C F G
== Inorder ==
H D I B J E A F C G
== Postorder ==
H I D J E B F G C A
== Levelorder ==
A B C D E F G H I J
// Practice3
// 트리 구조 복습 / 구현
import java.util.LinkedList;
import java.util.Queue;
class Node2 {
char data; // 데이터 값
Node2 left; // 왼쪽 자식 노드
Node2 right; // 오른쪽 자식 노드
Node2 parent; // 부모 노드
public Node2(char data, Node2 left, Node2 right, Node2 parent) { // 생성자
this.data = data;
this.left = left;
this.right = right;
this.parent = parent;
}
}
class BinaryTree3 {
Node2 head; // 헤드
BinaryTree3(char[] arr) { // 생성자
Node2[] nodes = new Node2[arr.length];
for (int i = 0; i < arr.length; i++) {
nodes[i] = new Node2(arr[i], null, null, null);
} // 각각의 노드들 초기화 시켜 놓가
for (int i = 0; i < arr.length; i++) { // 자식 노드에 대한 인덱스 찾기
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < arr.length) { // 범위 비교
nodes[i].left = nodes[left];
nodes[left].parent = nodes[i]; // 부모쪽도 연결!
}
if (right < arr.length) { // 범위 비교
nodes[i].right = nodes[right];
nodes[right].parent = nodes[i]; // 부모 쪽도 연결!
}
}
this.head = nodes[0]; // 헤드에다 루트 노드
}
public Node2 searchNode(char data) {
Queue<Node2> queue = new LinkedList(); // 큐를 만듬
queue.add(this.head); // 탐색 시점은 헤드로부터 출발
while (!queue.isEmpty()) { // 큐가 비어있지 않을 때까지 반복
Node2 cur = queue.poll(); // 큐에 데이터 꺼내기
if (cur.data == data) { // 찾고자 하는 데이터이면
return cur; // 현재 위치의 노드 반환
}
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
return null;
}
public Integer checkSize(char data) { // 데이터가 해당하는 노드로부터의 사이즈를 체크해서 반환
Node2 node = this.searchNode(data); // 해당 노드를 먼저 찾아줌
Queue<Node2> queue = new LinkedList(); // 큐 구조 이용
queue.add(node);
int size = 0;
while (!queue.isEmpty()) { // 큐가 빌 때까지
Node2 cur = queue.poll(); // 큐에서 데이터를 꺼낸다.
if (cur.left != null) { // 왼쪽이 비어있지 않으면
queue.offer(cur.left); // 큐에다 넣어줌
size++; // 순회 가능할 때마다 사이즈 늘어남
}
if (cur.right != null) { // 오른쪽이 비어있지 않으면
queue.offer(cur.right); // 큐에다 넣어줌
size++; // 순회 가능할 때마다 사이즈 늫어남
}
}
return size + 1;
}
}
public class Practice3 {
public static void main(String[] args) {
char[] arr = new char[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (char)('A' + i);
}
BinaryTree3 bt = new BinaryTree3(arr);
// Root node
System.out.println("Root: " + bt.head.data); // 루트 노드 출력
// B's child node
Node2 B = bt.searchNode('B');
if (B.left != null) { // 왼쪽 자식 노드가 비어있지 않으면
System.out.println("B -> left child: " + B.left.data); // 출력
}
if (B.right != null) { // 오른쪽 자식 노드가 비어있지 않으면
System.out.println("B -> right child: " + B.right.data); // 출력
}
// F's parent node
Node2 F = bt.searchNode('F');
System.out.println("F -> parent: " + F.parent.data);
// Leaf node
System.out.print("Leaf node: "); // 자식 노드가 없는 노드들
for (int i = 0; i < arr.length; i++) {
Node2 cur = bt.searchNode((char)('A' + i)); // 각각의 노드들을 찾는다.
if (cur.left == null && cur.right == null) { // 찾은 각각의 노드들에 대한 자식노드들을 찾는다. (리프노드 찾기)
System.out.print(cur.data + " "); // 출력
}
}
System.out.println();
// E's Depth
Node2 E = bt.searchNode('E'); // 루트노드부터 E라는 노드까지의 간선 (몇번 거침?)
Node2 cur = E;
int cnt = 0;
while (cur.parent != null) { // 부모가 비어있지 않을 때까지
cur = cur.parent; // 부모로 이동!
cnt++; // 개수 +1 (간선의 길이)
}
System.out.println("E depth: " + cnt);
// Level2 Node
System.out.print("Level2 Node: ");
for (int i = 0; i < arr.length; i++) {
Node2 target = bt.searchNode((char)('A' + i)); // 각각의 노드들을 찾아준다.
cur = target;
cnt = 0;
while (cur.parent != null) { // 리프노드까지
cur = cur.parent; // 부모 노드로 이동
cnt++; // 개수 +1 (간선의 길이)
}
if (cnt == 2) { // 레벨 2에 해당하는 노드들
System.out.print(target.data + " ");
}
}
System.out.println();
// Height
int maxCnt = Integer.MIN_VALUE; // 최대 깊이를 찾기 위해 최솟값을 넣어준다.
for (int i = 0; i < arr.length; i++) {
Node2 target = bt.searchNode((char)('A' + i)); // 각각의 노드들을 찾아준다.
cur = target;
cnt = 0;
while (cur.parent != null) {
cur = cur.parent;
cnt++;
}
if (maxCnt < cnt) { // maxCnt와 비교해준다.
maxCnt = cnt; // 가장 큰 depthr값이 들어간다.
}
}
System.out.println("Height: " + maxCnt);
// B's Size
int size = bt.checkSize('B');
System.out.println("B size = " + size);
}
}
<실행 결과>
Root: A
B -> left child: D
B -> right child: E
F -> parent: C
Leaf node: F G H I J
E depth: 2
Level2 Node: D E F G
Height: 3
B size = 6
// Practice1 (난이도 하)
// 종이 접기
// 종이를 반으로 접었을 때, 안으로 파인 부분은 0, 볼록 튀어나온 부분은 1이라고 하자.
// 종이를 접을 때는 오른쪽에서 왼쪽으로 접는다.
// 종이를 N번 접었을 때의 접힌 상태(0 또는 1)를 출력하는 문제를 작성하세요.
// 입출력 예시
// 입력: 1
// 출력: 0
// 입력: 2
// 출력: 0, 0, 1
// 입력: 3
// 출력: 0, 0, 1, 0, 0, 1, 1
public class Practice1 {
public static void solution(int n) {
int[] binaryTree = new int[(int)Math.pow(2, n)];
binaryTree[0] = 0;
for (int i = 0; i < (int) Math.pow(2, n - 1) - 1; i++) {
binaryTree[i * 2 + 1] = 0;
binaryTree[i * 2 + 2] = 1;
}
inOrder(binaryTree, 0);
System.out.println();
}
public static void inOrder(int[] arr, int idx) {
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < arr.length - 1) {
inOrder(arr, left);
}
System.out.print(arr[idx] + " ");
if (right < arr.length - 1) {
inOrder(arr, right);
}
}
public static void main(String[] args) {
// Test code
solution(1);
solution(2);
solution(3);
}
}
// Practice2
// 각각의 에지에 가중치가 있는 포화 이진 트리가 있다.
// 루트에서 각 리프까지의 경로 길이를 모두 같게 설정하고,
// 이 때, 모든 가중치들의 총합이 최소가 되도록 하는 프로그램을 작성하세요.
class BinaryTree {
int h;
int[] arr;
int res;
public BinaryTree(int h, int[] w) {
this.h = h;
// 이렇게 만들고 0번 위치 인덱스는 사용 X
arr = new int[(int)Math.pow(2, h + 1)];
res = 0;
// 포화 이진 트리의 간선의 수는 노드 수 - 1로 2부터 저장
for (int i = 2; i < (int)Math.pow(2, h + 1); i++) {
arr[i] = w[i - 2];
}
}
// 하단 부터 형제 노드의 간선을 맞춰 나가면서 진행
public int dfs(int idx, int h) {
if(this.h == h) {
res += arr[idx];
return arr[idx];
}
int left = dfs(idx * 2, h + 1);
int right = dfs(idx * 2 + 1, h + 1);
res += arr[idx] + Math.abs(left - right);
return arr[idx] + Math.max(left, right);
}
}
public class Practice2 {
public static void solution(int h, int[] w) {
BinaryTree bt = new BinaryTree(h, w);
bt.dfs(1, 0);
System.out.println(bt.res);
}
public static void main(String[] args) {
// Test code
int h = 2;
int[] w = {2, 2, 2, 1, 1, 3};
solution(h, w);
System.out.println();
h = 3;
w = new int[]{1, 2, 1, 3, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1};
solution(h, w);
}
}