[소스 코드]
https://github.com/kyuuuunmi/DataStructure_TREE
[설명]
대학생 연합 IT 벤처 창업 동아리 S.O.P.T (Shout Our Passion Together - http://sopt.org) 에서 내부적으로 진행하는 전공 과목 기초 스터디 자료입니다.
이번주에 다룬 내용은 이진 트리 및 우선순위 큐에 대한 내용입니다.
스터디 자료는 다음과 같은 순서대로 올라갈 예정입니다.
1. 데이터 구조 및 알고리즘
2. 운영체제
3. 네트워크
[SOPT] 데이터 구조 및 알고리즘 스터디 - #04 : 트리 기초, 이진 트리, 우선순위 큐
1. 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0
0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 1
0 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0
1 0 1 0 1 0 1 0 1 0 1 0 0 1 0 1
DATA STRUCTURES
@Override
public void add(Node<T> node) {
Node pointer = header;
while (pointer.next != null) {
pointer = pointer.next;
}
pointer.next = node;
size++;
}
Tree · Binary Tree · Binary Search Tree · 우선순위 큐
A
B
H
G
front
rear
2. TABLE OF CONTENTS
SHOUT OUR PASSION TOGETHER DATA STRUCTURES INDEX
004
005
019
021
024
027
046
047
051
053
055
066
069
Tree - 개요
Tree - 용어
Binary Tree - 개요
Binary Tree - 성질 / 종류
Binary Tree - 구현
Binary Tree - 순회
Binary Search Tree - 개요
Binary Search Tree – 코드 분석
Binary Search Tree – 성능 분석
우선순위 큐 - 개요
우선순위 큐 - 힙 정렬
우선순위 큐 - 코드 분석
우선순위 큐 - 성능 분석
19. Binary Tree
개요
Study - Data Structures
트리의 노드 구조를 일정하게 정의하여 구현과 연산이 쉬움
모든 노드가 0개 이상 2개 이하의 서브 트리를 가지는 트리
20. Study - Data Structures
Binary Tree
개요
왼쪽 서브 트리 : 이진 트리
오른쪽 서브 트리 : 이진 트리
21. Binary Tree
성질
Study - Data Structures
n 개의 노드를 가지는 이진 트리의 높이는 최소 log ₂ n, 최대 n 이다
높이가 h 인 이진 트리가 가질 수 있는 노드의 갯수는 최대 h 개 이다
n 개의 노드를 가진 이진 트리는 항상 (n-1) 개의 간선을 가진다
22. Study - Data Structures
Binary Tree
종류 – 포화 이진 트리(Full Binary Tree)
루트를 1번으로 (2^h-1)까지 정해진 위치 번호를 가짐
모든 레벨에 노드의 차수가 2로 차 있는 이진 트리
높이가 h일 때, 최대 노드 개수를 가진 이진 트리
왼쪽에서 오른쪽으로 번호를 붙임
23. Study - Data Structures
Binary Tree
종류 – 완전 이진 트리(Complete Binary Tree)
레벨 h 에서는 왼쪽부터 순서대로 채워지는 이진 트리
레벨 1부터 h-1까지의 노드가 모두 채워져 있는 트리
24. Study - Data Structures
Binary Tree
구현 – 배열 표현법
A
B
C
D
E
Index
0
1
2
3
4
5
6
7
8
B
A
C
D E
B
A
C
D
A
B
C
D
Index
0
1
2
3
4
5
6
7
8
각 노드에 번호를 붙여 그 번호를 배열 인덱스로 삼아 배열에 데이터를 저장하는 방법
모든 이진 트리를 포화 이진 트리로 가정
25. Study - Data Structures
Binary Tree
구현 – 배열 표현법
A
B
C
D
E
Index
0
1
2
3
4
5
6
7
8
B
A
C
D E
노드 i의 왼쪽 자식 노드 인텍스 = 2i
노드 i의 부모 노드 인텍스 = i/2
노드 i의 오른쪽 자식 노드 인텍스 = 2i+1
1
2 3
4 5
26. Study - Data Structures
Binary Tree
구현 – 링크 표현법
B
A
C
D E
B
A
C
D
포인터를 이용해 부모 노드가 자식 노드를 가리키게 하는 방법
A
B C
D E
A
B
C
D
27. Study - Data Structures
Binary Tree
이진 트리의 순회
노드의 접근 순서에 따라 세 가지 방법이 존재 : 특정 노드와 자식 노드의 순서를 고려
트리의 모든 노드들을 체계적으로 방문하여 각 노드가 가지고 있는 데이터를 목적에 맞게 처리
전위 순회 (Preorder Traversal) : VLR
중위 순회 (Inorder Traversal) : LVR
후위 순회 (Postorder Traversal) : LRV
28. Study - Data Structures
Binary Tree
이진 트리의 순회 – 전위 순회
루트를 먼저 방문
29. Study - Data Structures
Binary Tree
이진 트리의 순회 – 전위 순회
왼쪽 서브 트리 방문
30. Study - Data Structures
Binary Tree
이진 트리의 순회 – 전위 순회
오른쪽 서브 트리 방문
31. Study - Data Structures
Binary Tree
이진 트리의 순회 – 전위 순회
1
2
3 4
5
6 7
32. Study - Data Structures
Binary Tree
이진 트리의 순회 – 중위 순회
왼쪽 서브 트리 방문
33. Study - Data Structures
Binary Tree
이진 트리의 순회 – 중위 순회
루트 노드를 방문
34. Study - Data Structures
Binary Tree
이진 트리의 순회 – 중위 순회
오른쪽 서브 트리 방문
35. Study - Data Structures
Binary Tree
이진 트리의 순회 – 중위 순회
4
2
1 3
6
5 7
36. Study - Data Structures
Binary Tree
이진 트리의 순회 – 후위 순회
왼쪽 서브 트리 방문
37. Study - Data Structures
Binary Tree
이진 트리의 순회 – 후위 순회
오른쪽 서브 트리 방문
38. Study - Data Structures
Binary Tree
이진 트리의 순회 – 후위 순회
루트 노드를 방문
39. Study - Data Structures
Binary Tree
이진 트리의 순회 – 후위 순회
7
3
1 2
6
4 5
40. Study - Data Structures
Binary Tree
이진 트리의 순회 – 레벨 순회
각 노드를 레벨 순으로 검사하는 순회 방법
동일 레벨인 경우 좌에서 우로, 위에서부터 아래로 순회
큐를 사용하여 트리 순회를 구현할 수 있다
41. Study - Data Structures
Binary Tree
이진 트 순회 코드 분석
private void inorder(Node r)
{
if (r != null)
{
inorder(r.getLeft());
System.out.print(r.getData().id +" ");
inorder(r.getRight());
}
}
private void preorder(Node r)
{
if (r != null)
{
System.out.print(r.getData().id +" ");
preorder(r.getLeft());
preorder(r.getRight());
}
}
private void postorder(Node r)
{
if (r != null)
{
postorder(r.getLeft());
postorder(r.getRight());
System.out.print(r.getData().id +" ");
}
}
중위 순회
전위 순회
후위 순회
42. Study - Data Structures
산술식을 트리 형태로 표현한 것
Binary Tree
순회 응용 – 수식트리
a x
b c
-
중위순회 : a - b × c
후위순회 : :a b c × -
전위순회 : - a × b c
43. Study - Data Structures
산술식을 트리 형태로 표현한 것
Binary Tree
순회 응용 – 수식트리
a x
b c
-
중위순회 : a - b × c
후위순회 : :a b c × -
전위순회 : - a × b c
수식 트리의 계산
후위 순회 사용
44. 구조화된 문서 출력 폴더 용량 계산
Study - Data Structures
Binary Tree
사례
46. Study - Data Structures
Binary Search Tree
개요 - 이진 트리에 탐색 조건을 추가한자료 구조
오른쪽 서브 트리에 있는 원소의 키들은 그 루트의 키보다 큼
왼쪽 서브 트리에 있는 원소의 키들은 그 루트의 키보다 작음
모든 요소는 서로 다른 유일한 키를 가진다는 가정을 함
왼쪽 서브 트리와 오른쪽 서브 트리 또한 이진 탐색 트리의 성격을 띔
47. Study - Data Structures
코드 분석 - 삽입
class BST<T extends Data>
{
private Node root;
public BST() { root = null; }
public boolean isEmpty() {return root == null; }
public void insert(T data) {
root = insert(root, data);
}
private Node insert(Node node, T data) {
if (node == null)
node = new Node(data);
else {
if (data.compareTo(node.getData()) <0 )
node.left = insert(node.left, data);
else
node.right = insert(node.right, data);
}
return node;
}
}
Binary Search Tree
트리의 root 초기화
삽입된 노드를 자식으로 가지는 루트노드를 리턴
삽입될 위치를 찾아서 노드를 삽입
48. Study - Data Structures
public void delete(T data) {
if (isEmpty()) {
System.out.println("Tree Empty");
return;
}
Node p = root, p2 = null;
while (p != null &&
p.getData().compareTo(data) != 0) {
p2 = p;
if (data.compareTo(p.getData()) < 0) p = p.getLeft();
else p = p.getRight();
}
if (p == null) {
System.out.println(data + " is not present");
return;
}
if (p.getLeft() == null && p.getRight() == null) {
if (p2 != null) {
if (p2.getLeft() == p) p2.setLeft(null);
else p2.setRight(null);
}
else root = null;
}
…
코드 분석 - 삭제
Binary Search Tree
노드 설정
data를 갖는 노드 p 탐색
찾는 키가 없는 경우
삭제할 노드의 단말 노드 차수가 0인 경우
부모의 자식 필드를 NULL로 설정
49. Study - Data Structures
…
else if (p.getLeft() == null || p.getRight() == null) {
Node c = p.getLeft() == null ?
p.getRight() : p.getLeft();
if (p2 != null) {
if (p2.getLeft() == p) p2.setLeft(c);
else p2.setRight(c);
}
else
root = c;
}
else if (p.getLeft() != null && p.getRight() != null) {
Node q2 = p;
Node q = p.getRight();
while (q.getLeft() != null) {
q2 = q;
q = q.getLeft();
}
if(q2.getLeft() == q) q2.setLeft(q.getRight());
else q2.setRight(q.getLeft());
p.setData(q.getData());
}
}
차수가 1인 노드의 삭제
c : 자식 노드
차수가 2인 노드의 삭제
오른쪽 서브 트리에서 후계자검색
후계자 찾아 왼쪽으로 이동
후계자(q)의 부모와 자식을 연결
코드 분석 - 삭제
Binary Search Tree
후계자 키 값을 현재 노드에 복사
부모의 삭제 : 자식 필드를 c로 설정
50. Study - Data Structures
코드 분석 - 탐색
Binary Search Tree
public boolean search(T val) {
return search(root, val);
}
private boolean search(Node root, T data) {
boolean found = false;
Node pp;
Node p = root;
while ((p != null) && !found) {
pp = p;
if (data.compareTo(p.getData()) < 0)
p = pp.getLeft();
else if (data.compareTo(p.getData()) > 0)
p = pp.getRight();
else {
found = true;
break;
}
}
return found;
}
51. Binary Search Tree
성능 분석
Study - Data Structures
기본
검색, 삽입, 삭제 등의 연산에 대한 시간 복잡도는 트리의 높이 h에 비례
연산 시간
평균 시간 복잡도
O (log n)
1. 최선의 경우 : 이진 트리가 균형적으로 생성되어 있는 경우에 해당
→ h = log n
2. 최악의 경우 : 트리를 구성하는 요소가 한 쪽으로 치우쳐진 경사 이진 트리
→ h = n
53. Study - Data Structures
우선순위 큐
개요
IN OUT
1 2 3
우선순위를 가진 항목들을 저장하는 큐
우선 순위가 높은 데이터가 먼저 나가게 된다
54. Study - Data Structures
우선순위 큐
사례
시물레이션 시스템 네트워크 트래픽 제어 운영 체에서의 작업
스케쥴링
http://sopt.org
…
Prev. SFP
Return Address
Parameters
+
Local Variables
55. Heap
개요
삭제 연산 시 항상 루트 노드 요소를 삭제하여 반환
여러 개의 값 중에서 가장 큰 값 (혹은 가장 작은 값) 을 빠르게 찾기 위해 설계된 자료 구조
히프 정렬은 요소의 개수만큼 삭제 연산을 수행하여 내림차순 / 오름차순으로 정렬 수행
Study - Data Structures
최대 히프에서는 항상 가장 큰 요소가 루트 노드가 됨
56. Study - Data Structures
수행 과정
10
69
22
30
318162
22
69
2
31
3081610
- 69 10 30 2 16 8 31 22
Heap
57. Study - Data Structures
수행 과정
10
22
30
318162
22
31
30
281610
- 69
Heap
58. Study - Data Structures
수행 과정
22 30
281610
22
30
8
21610
- 31 69
Heap
59. Study - Data Structures
수행 과정
22 8
21610
16
22
8
210
- 30 31 69
Heap
60. Study - Data Structures
수행 과정
16 8
210
10
16
8
2
- 22 30 31 69
Heap
61. Study - Data Structures
수행 과정
10 8
2
2
10
8
- 16 22 30 31 69
Heap
62. Study - Data Structures
수행 과정
2 8 2
8
- 10 16 22 30 31 69
Heap
63. Study - Data Structures
수행 과정
2
2
- 8 10 16 22 30 31 69
Heap
64. Study - Data Structures
수행 과정
- 2 8 10 16 22 30 31 69
Heap
65. Study - Data Structures
수행 과정
- 2 8 10 16 22 30 31 69
Heap
공백 히프가 되었으므로 정렬 종료
66. Study - Data Structures
코드 분석
Heap
public class Heap {
private Node[] node;
private int MAXSIZE = 50;
private int length;
public Heap() {
node = new Node[MAXSIZE];
length= 0;
}
public Node getNode(int i) { return node[i]; }
public int getLength() { return length; }
public boolean isEmpty() { return length == 0; }
public boolean isFull() { return MAXSIZE == length; }
…
}
Node 타입의 배열 선언
MAXSIZE 크기의 배열 생성 및 length 초기화
객체의 속성을 받아오는 메소드
배열의 크기를 알 수 있는 메소드
67. Study - Data Structures
코드 분석 - 삽입
Heap
…
public void insert(Node node) {
if (isFull()) {
System.out.println("Heap is full");
return;
}
int i = ++length;
while (i != 1 && node.getData()
.compareTo(this.node[i / 2].getData()) > 0) {
this.node[i] = this.node[i / 2];
i = i / 2;
}
this.node[i] = node;
}
…
노드의 삽입이 가능한지 판별
i 에 1증가한 length를 넣음
삽입할 node와 해당 부모 노드의 크기비교
-> 삽입할 node보다 작으면 자식노드로 이동
해당되는 i 인덱스에 node 삽입
68. Study - Data Structures
코드 분석 - 삭제
Heap
public Node delete() {
Node item = node[1];
node[1] = node[length--];
int i = 2, largest;
while (i <= length) {
if (i < length &&
node[i].getData()
.compareTo(node[i + 1].getData()) < 0)
largest = i + 1;
else largest = i;
if (node[largest /2].getData().
.compareTo(node[largest].getData()) > 0)
break;
Node tmp = node[largest / 2];
node[largest / 2] = node[largest];
node[largest] = tmp;
i = largest * 2;
}
return item;
}
}
우선순위가 가장 높은 원소 삭제
삭제할 원소는 item에 저장
노드가 내려가면서 원소 재배열
우선순위가 가장 낮은 단말 노드를 삭제된 노드와 변경
69. Heap
성능 분석
Study - Data Structures
메모리 사용 공간
O (n) : n 개의 원소에 대하여 n 개 + 힙을 구현하기 위한 n 개의 메모리
연산 시간
평균 시간 복잡도
O (n log n)
n 개의 요소에 대해 완전 이진 트리의 레벨은 log (n + 1) 이므로, 힙 구성시간은 O (log n) 을 따른다
따라서, 힙을 구성하고 다시 순서대로 뽑아 정렬하는 시간은 O (n log n) 이다