Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[테크니컬 라이팅] 종이(최우종) 미션 제출합니다. #568

Open
wants to merge 3 commits into
base: dwax1324
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Screenshot 2024-11-05 at 12.29.00.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshot 2024-11-05 at 12.46.36.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshot 2024-11-05 at 12.50.59.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshot 2024-11-05 at 12.52.21.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshot 2024-11-05 at 12.53.24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
254 changes: 254 additions & 0 deletions tech.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
# 트리

이번 테크니컬 라이팅에서 트리 자료구조에 대해 알아보려고 합니다. 하지만 그 전에 자료의 표현방식부터 알아봅시다.

컴퓨터과학에 있어서 정보는 굉장히 중요합니다. 저장되는 값들은 의미가 있어야하고 인간이 이해할 수 있어야합니다. 저희는 컴퓨터를 통해 자료를 저장하고, 자료를 조작하여 원하는 결과를 얻어냅니다.

![img](./Screenshot%202024-11-05%20at%2012.29.00.png)

데이터는 크게 정성적 데이터 정량적 데이터로 나눌 수 있습니다.
정성적 데이터와는 다르게 정량적 데이터는 수치적인 측정이 포함되어 있습니다. 여기에서의 수치는 또 연속적인 것과 이산적인 것으로 나뉘게 됩니다.
이산적인 데이터는 그래프로 표현하기에 아주 유리합니다.


트리를 정의하기 위해서는 정점과 간선이 무엇인지 알아야합니다. 정점(Node, Vertex), 간선(Edge,Link) 는 수학적인 개념입니다. 그래프 이론 혹은 이산 수학을 배울 때 주로 등장합니다. 정점은 하나의 상태를 나타냅니다. 간선은 정점과 정점 사이의 전이를 나타냅니다. 이들이 모여서 하나의 그래프가 형성됩니다.

하나의 정점에서는 상태를 가질 수 있습니다. 하나의 간선을 통해 하나의 정점에서 다른 정점으로 이동할 수 있습니다. 이는 곧 상태 변화의 가능성을 암시합니다. 간선은 상태를 변화할 수 있도록 도와주는 행위입니다.

어떠한 상태가 주어졌을 때, 함수를 정의할 수 있습니다. 이에 따른 결과가 나온다면 그건 또 다른 상태입니다.
함수 f(x)가 있을 때, 매개변수인 x는 상태이고,함수 f는 간선이며, 반환값인 y는 또 다른 상태가 되는 것입니다.

이러한 표현이 문제 해결에 많은 도움이 되는데요.
문제를 정의한다는 것은 곧 정점과 간선의 집합인 상태 공간을 정의한다는 것과 동치가 됩니다.
문제의 상태공간을 잘 정의했다면, 어떠한 입력이 주어졌을 때 원하는 결과값이 도출될 것입니다.
문제 속에 숨어있는 암시적 그래프를 잘 찾아내고 이에 대한 상태공간을 정의할 수 있다면 문제해결 과정이 수월해질 것입니다.


트리는 그래프는에 속합니다.
그래프는 정점과 간선으로 이루어진 집합이라고 한다면, 트리는 n개의 정점과 n-1개의 간선으로 이루어져 있습니다.
다른 말로 트리에서는 사이클이 존재할 수 없습니다.

어떤 정점을 루트 노드로 정의하면 트리에는 계층적인 구조가 나타나게 됩니다.

![img](./Screenshot%202024-11-05%20at%2012.46.36.png)

루트 노트(root node): 부모가 없는 노드, 트리는 하나의 루트 노드만을 가진다.
단말 노드(leaf node): 자식이 없는 노드(차수가 0인 노드), '말단 노드' 또는 '잎 노드'라고도 부른다.
내부(internal) 노드 : 단말노드가 아닌 노드.
간선(edge): 노드를 연결하는 선(link, branch 라고도 부름)
형제(sibling): 같은 부모를 가지는 노드
노드의 크기(size): 자신을 포함한 모든 자손 노드의 개수
노드의 깊이(depth): 루트에서 어떤 노드에 도달하기 위해 거쳐야 하는 간선의 수
노드의 레벨(level): 트리의 특정 깊이를 가지는 노드의 집합
노드의 차수(degree): 노드의 서브트리 수
트리의 차수(degree of tree): 트리의 최대 차수
트리의 높이(깊이)(height): 루트 노드에서 가장 깊숙이 있는 노드의 깊이, max{노드레벨}



트리의 모양에 따라 여러가지 이름으로 불리게 됩니다.

트리만의 순회 방법이 존재합니다.

n-진 트리란 각 노드가 최대 n개의 자식 노드를 갖는 것을 말합니다.

![img](./Screenshot%202024-11-05%20at%2012.50.59.png)


트리가 한쪽으로 치우쳐져 있는 모습을 보인다면 unbalnaced하다고 합니다.

![img](./Screenshot%202024-11-05%20at%2012.52.21.png)




이진 검색트리란 이진 트리의 특성을 이용해 구현한 자료구조를 칭합니다.

![img](./Screenshot%202024-11-05%20at%2012.53.24.png)


트리는 추상적인 데이터타입입니다. 어떻게 구현하느냐는 구현자의 마음에 따라 다릅니다. 하지만 보통 인접행렬,인접리스트,연결리스트 사용하는 방식으로 나뉩니다.

```java
public class TreeNode {

private TreeNode left;

private TreeNode right;

private Object data;



public TreeNode(Object item){

left = null;

right = null;

data = item;

}



//자신과 왼쪽 자식 노드(sub)와 연결해주는 method

public void makeLeftSubTree(TreeNode sub){

if(this.left != null) this.left = null;

this.left = sub;

}



//자신과 오른쪽 자식 노드(sub)와 연결해주는 method

public void makeRightSubTree(TreeNode sub){

if(this.right != null) this.right = null;

this.right = sub;

}



//자신의 data를 반환하는 함수

public Object getData(){

return this.data;

}



//자신의 왼쪽 자식노드를 반환하는 함수

public TreeNode getLeftSubTree(){

return this.left;

}



//자신의 오른쪽 자식노드를 반환하는 함수

public TreeNode getRightSubTree(){

return this.right;

}

}

```



```java
import java.util.*;

public class TreeOrder2Matrix {
static int n;
static int[][] tree;

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
tree = new int[n][2]; //tree 저장을 위한 2차원 배열

for (int i = 0; i < n; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
tree[a][0] = b; // 0은 left
tree[a][1] = c; // 1은 right
}

System.out.println("전위 순회");
preOrder(0);

System.out.println("\n중위 순회");
inOrder(0);

System.out.println("\n후위 순회");
postOrder(0);
}

//전위순회 Preorder : Root -> Left -> Right
public static void preOrder(int x) {
if (tree[x][0] == -1 && tree[x][1] == -1) { //왼쪽 자식이나 오른쪽 자식이 없다면 (-1이라면) 순회X
System.out.print(x + " ");
} else {
System.out.print(x + " ");
if (tree[x][0] != -1) {
preOrder(tree[x][0]);
}
if (tree[x][1] != -1) {
preOrder(tree[x][1]);
}
}
}

//중위 순회 Inorder : Left -> Root -> Right
public static void inOrder(int x) {
if(tree[x][0] == -1 && tree[x][1] == -1) {
System.out.print(x + " ");
} else {
if(tree[x][0] != -1) {
inOrder(tree[x][0]);
}
System.out.print(x + " ");
if(tree[x][1] != -1) {
inOrder(tree[x][1]);
}
}
}

//후위순회 Postorder : Left -> Right -> Root
public static void postOrder(int x) {
if(tree[x][0] == -1 && tree[x][1] == -1) {
System.out.print(x + " ");
} else {
if(tree[x][0] != -1) {
postOrder(tree[x][0]);
}
if(tree[x][1] != -1) {
postOrder(tree[x][1]);
}
System.out.print(x + " ");
}
}

}
```



트리만 보면 구현하기도 귀찮고, 비선형 자료구조여서 한 눈에 파악이 되는 것이 아니기 때문에 쉽게 이해가 되지 않을수가 있습니다.

이러한 불편함을 감수하고 트리를 사용하고 가르치는 이유가 무엇일까요? 바로 효율성 때문입니다.

트리를 역시 이산적인 데이터 구조이기 때문에 정점을 통해 데이터를 표현할 수 있고, 간선을 통해 데이터간의 상관관계를 나타낼 수 있습니다. 구현하기에는 까다로운 부분이 있지만, 한번 구현하고 나서 적당히 추상화하고 나면 아주 유용한 자료구조가 됩니다. 대부분의 트리는 log(N) 수준의 시간복잡도를 지원합니다. 이는 이진탐색의 특성 때문인데요, 이진탐색을 진행할 때, 목표하는 값이 현재 탐색 값보다 작으면, 현재 탐색값보다 더 큰값은 더이상 살펴볼 필요가 없습니다. 1차원 배열을 이분탐색 한다고 가정하면 매 탐색마다 절반의 데이터가 줄어듭니다. 이는 이분탐색이 logN이 될 수 있는 이유이기도 합니다.

이를 그대로 트리에 적용한 것이 이진탐색트리입니다. 하나의 노드에서 목표값과 현재 상태의 값을 비교하여서, 왼쪽 간선으로 보낼지 오른쪽 간선으로 보낼지 결정할 수 있습니다. 위의 예시와 같이, 만약 목표값이 현재 탐색값보다 작다면 오른쪽 간선 아래에 있는 서브트리는 살펴볼 필요가 없습니다. 이 서브트리에 있는 정점들은 모두 현재 정점보다 큰 값이기 때문입니다.

매번 1/2씩 줄어드는 이진탐색의 특성 때문에, 이진 트리의 상태공간을 쉽게 정의할 수 있습니다. 어떤 값을 찾으려고 할 때, 그 탐색의 깊이는 전체 데이터가 n이라고 했을 때, 깊어봤자 logN입니다.

1차원 배열을 써서 선형 탐색을 해야하면 O(N) 시간복잡도가 걸리는데 트리는 O(logN)만에 찾을 수 있습니다. 1차원 배열이라도 매번 이진탐색을 사용하여 logN의 탐색 시간복잡도를 가질 수 있지만, 트리 자료구조는 삽입, 삭제, 수정 또한 log(N)의 시간복잡도가 걸린다는 것이 장점입니다.

블라블라



몇 가지 유용한 트리 자료구조를 소개하면서 글을 마치겠습니다.


B Tree

https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Tree