용어
- 루트(root) : 트리 구조 중 최상위에 존재하는 노드 (1을 가리킴)
- 노드(node) : 트리에서 각각의 구성 요소
- 레벨(level) : 트리에서 각각의 층을 나타내는 단어(루트 노드 : 0)
- 형제 노드(sibling) : 같은 부모 노드를 가지는 모든 노드
- 간선(edge) : 노드와 노드를 연결하는 선
- 부모 노드(parent node) : 한 노드를 기준으로 바로 상위에 존재하는 노드
- 자식 노드(child node) : 한 노드를 기준으로 바로 하위에 존재하는 노드
- 높이(heigh) : 트리 중 최고 레벨
- leaf(잎) : 자식이 없는 node
- subtree : 큰 tree에 속한 작은 tree
- 노드의 깊이(depth) : 루트 노드에서 어떤 노드에 도달하기 위해 거쳐야 하는 간선의 수(ex : D의 depth : 2)
- 노드의 차수(degree) : 자식 노드의 개수 ( ex : B의 degree - 2, C의 degree - 0)
- 트리의 차수(degree of tree) : 트리의 최대 차수 ( ex : 위 트리의 차수는 2이다)
트리의 노드는 self-loop가 존재 해서는 안된다.
N개의 노드를 갖는 트리는 항상 N-1 개의 간선(edge)을 갖는다.
모든 자식 노드는 한 개의 부모 노드만을 갖는다.
Node 클래스에 3개의 변수를 만든다.
public class Node {
Object data;
Node left;
Node right;
}
1) 이진 탐색 트리의 노드에 저장된 키(key)는 유일하다.
2) 부모의 키가 왼쪽 자식 노드의 키보다 크다.
3) 부모의 키가 오른쪽 자식 노드의 키보다 작다.
4) 왼쪽과 오른쪽 서브 트리도 이진 탐색 트리이다.
5) 최대 2개의 자식을 가진다.
이진 검색 트리의 장점 : 룩업 연산(트리에 있는 특정 노드의 위치를 알아내는 연산)을 빠르고 간단하게 처리할 수 있다.
한단계 올라갈때마다 절반이 줄어들기 때문에, 시간복잡도는 O(log n)이다.
이진 탐색 트리는 효율적인 탐색을 위해 고안된 트리이다.
전위(pre-order), 중위(in-order), 후위(post-order) 순회가 있다.
전위 순회(pre-order) : root 노드를 먼저 순회한 이후, '왼쪽 -> 오른쪽' 순으로 순회하는 방법.
중위 순회(in-order) : 왼쪽 가장 하위 노드를 먼저 순회한 이후, 'root -> 오른쪽' 순으로 순회하는 방법.
후위 순회(post-order) : 왼쪽 가장 하위 노드를 먼저 순회한 이후, '오른쪽 하위 노드 -> root 노드' 순으로 순회하는 방법
void addLeft(Node node)
현재 노드의 좌측에 노드 연결 정보를 추가한다.
void addRight(Node node)
현재 노드의 우측에 노드 연결 정보를 추가한다.
void deleteLeft()
현재 노드의 좌측 노드 연결 정보를 삭제한다.
void deleteRight()
현재 노드의 좌측 노드 연결 정보를 삭제한다.
Node addNode(Object data)
노드를 새롭게 생성한다.(저장될 데이터는 data 변수 안에 존재하는 값)
void preOrder(Node node)
전위 순회 방법을 이용해 출력한다.
void inOrder(Node node)
중위 순회 방법을 이용해 출력한다.
void postOrder(Node node)
후위 순회 방법을 이용해 출력한다.
public class Tree {
int count;
public Tree() {
count = 0;
}
public class Node {
Object data;
Node left;
Node right;
// 생성 시 매개변수를 받아 초기화하는 방법으로만 선언 가능
public Node(Object data) {
this.data = data;
left = null;
right = null;
}
public void addLeft(Node node) {
left = node;
count++;
}
public void addRight(Node node) {
right = node;
count++;
}
public void deleteLeft() {
left = null;
count--;
}
public void deleteRight() {
right = null;
count--;
}
}
public Node addNode(Object data) {
Node n = new Node(data);
return n;
}
public void inorder(Node node) {
// node가 null이 아닐 때까지 재귀호출 반복
if(node != null) {
// left node 재귀호출을 다 돌고난 후 > 자기 자신 출력 > right node 재귀호출
inorder(node.left);
System.out.println(node.data);
inorder(node.right);
}
}
public void preorder(Node node) {
// node가 null이 아닐 때까지 재귀호출 반복
if(node != null) {
// 자기 자신 출력 > left node 재귀호출을 다 돌고난 후 > right node 재귀호출
System.out.println(node.data);
preorder(node.left);
preorder(node.right);
}
}
public void postorder(Node node) {
// node가 null이 아닐 때까지 재귀호출 반복
if(node != null) {
// left node 재귀호출을 다 돌고난 후 > right node 재귀호출 > 자기 자신 출력
postorder(node.left);
postorder(node.right);
System.out.println(node.data);
}
}
import Tree.*;
import Tree.Tree.Node;
public class Run {
public static void main(String[] args) {
// 트리 생성
Tree tree = new Tree();
// 노드 생성
Node node1 = tree.addNode(1);
Node node2 = tree.addNode(2);
Node node3 = tree.addNode(3);
Node node4 = tree.addNode(4);
Node node5 = tree.addNode(5);
Node node6 = tree.addNode(6);
Node node7 = tree.addNode(7);
// 트리 연결관계 생성
/* 트리 모양
* 1
* 2 3
* 4 5 6 7
*/
node1.addLeft(node2);
node1.addRight(node3);
node2.addLeft(node4);
node2.addRight(node5);
node3.addLeft(node6);
node3.addRight(node7);
// 순회
tree.preOrder(node1);
System.out.println();
tree.inOrder(node1);
System.out.println();
tree.postOrder(node1);
System.out.println();
// 삭제
node2.deleteLeft();
node3.deleteRight();
/* 삭제 이후 트리 모양
* 1
* 2 3
* 5 6
*/
// 순회
System.out.println();
tree.preOrder(node1);
System.out.println();
tree.inOrder(node1);
System.out.println();
tree.postOrder(node1);
System.out.println();
}
}
참고
https://readerr.tistory.com/35
https://haenny.tistory.com/345#google_vignette
https://code-lab1.tistory.com/8