트리 이진트리 이진탐색트리 -...
TRANSCRIPT
트리, 이진트리, 이진탐색트리
Tree
신찬수
트리란? • 자료를 계층적으로(hierarchically) 저장하기 위한 자료구조
리스트처럼 노드와 링크로 구성됨
• 계층적이라함은 노드 사이에 부모-자식 관계가 있음을 의미.
트리의 정의
• 트리 T는 부모-자식 관계로 노드의
집합을 표현한 자료구조:
– 부모노드가 없는 노드를 루트(root)
노드라 부른다.
– 루트노드를 제외한 모든 노드는 유일한
부모노드가 존재한다.
• 리프노드(leaf node),
내부노드(internal node)
• 에지(edge)
• 형제/ 조상/ 자손노드 (sibling/ ancestor/
descendent node)
• 부트리(subtree)
이진트리(binary tree)
• 트리 중에서 각 노드의 자식노드가 최대
두 개 이하인 트리를 특별히
이진트리(binary tree)라 부른다.
• 두 노드 u와 v 사이의 거리(distance)는 두
노드를 연결하는 경로(path)를 구성하는
에지의 개수이다.
• 노드 v의 높이(height)는 v의 자손 노드 중
가장 멀리 떨어진 리프 노드까지의
거리이다.
• 트리 T의 높이(height)는 루트 노드의
높이로 정의된다.
이진트리의 활용
• 산술식의 계산
72/)5*)43((
이진트리의 성질
• T : n개의 노드를 가지고 높이가 h인 트리
• d : T의 레벨 (루트노드의 레벨은 0이고, 차례로 증가한다)
• 레벨 d 에 있을 수 있는 최대 노드의 개수는 =
• T에 있을 수 있는 내부노드의 개수는 최소 _____________개이고,
최대 ______________개이다.
• T의 높이는 최소 __________이고, 최대 ____________이다.
이진트리의 표현법: 1차원 배열
• 힙(heap) 표현법과 같은 방법!
• 노드 v 가 T의 루트에 저장: A[0] = v
• 노드 v가 A[k]에 저장되어 있다면, 왼쪽 자식노드는 A[2k+1]에,
오른쪽 자식노드는 A[2k+2]에 저장
• 노드 v가 A[k]에 저장되어 있다면, 부모노드는 A[ ]에 저장
이진트리의 표현법: 1차원 배열
• 효율적인 표현법인가?
– 가장 안 좋은 트리 모양은? 3
9
0 8
1 2
2
5 6
3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
이진트리의 표현법: 노드 구조체
typedef struct treenode* node;
struct treenode {
int key;
node left, right, parent;
};
10
27 7
91 31 57
left
parent
right
key
2
4
1
3
이진트리의 표현법: 노드 구조체
1
2
4 5
3
5
이진트리의 표현법: 노드 구조체
2
4
1
3
5
5
typedef struct btree* tree;
struct btree {
node root;
int size;
}
Basic functions tree createBinaryTree( void ) {
tree T = (tree)malloc( sizeof (struct btree) );
T->root = null;
T->size = 0;
}
int height( node v) {
if ( v == null ) return -1;
else {
int h;
h = max ( height(v->left), height(v->right) );
return (h + 1);
}
방문법(traversal)
• 트리 T의 모든 노드를 빠지지 않고 방문하는 방법
• Preorder traversal: up-to-down, left-to-right
4
5
1
35 9
2 18
3 12
20
8
7
41 54 21
Postorder traversal
• down-to-up, left-to-right
4
5
1
35 9
2 18
3 12
20
8
7
41 54 21
Inorder traversal (이진트리)
• down-to-up, left-middle-right
/
*
+
7
- +
2 3 4
72/)5*)43((
5
Inorder traversal at binary tree
/
*
+
7
- +
2 3 4 5
void inorder( node v ) {
if ( v != null ) {
inorder( v->left );
printf( “ %c \n”, v->key );
inorder( v->right );
}
}
Euler Tour (이진트리)
/
*
+
7
- +
2 3 4 5
• 각 에지가 양방향 도로라고 생각하고, 루트노드에서 시작해 모든 방향의 도로를 정확히 한번씩 방문한 후 제자리로 돌아오는 방법.
• Preorder의 방문순서와 일치
이진탐색트리
Binary Search Tree
신찬수
Binary Search Tree • 이진트리 중에서 각 노드 v에 저장된 값이 왼쪽 부트리(subtree)에 저장된 값들보다 크거나 같고, 오른쪽 부트리에 저장된 값들보단 작을 때, 이 이진트리를 이진탐색트리라 부른다.
15
8
3 11
5 9
18
28
21 33
inorder 방문을 하게 되면? inorder( T->root );
void inorder( node v ) {
if ( v != null ) {
inorder( v->left );
printf( “ %c \n”, v->key );
inorder( v->right );
}
트리와 노드 구조체
typedef struct btree* tree;
struct btree {
node root;
int size;
}
typedef struct treenode* node;
struct treenode {
int key;
node left, right, parent;
};
탐색 • node search( tree T, int key )
– T에 key 값을 저장한 노드가 있다면 그 노드를 리턴하고, 없으면 null 리턴
– search( T, 11 ) search( T, 25 )
15
8
3 11
5 9
18
28
21 33
node search( tree T, int key ) {
node p = T->root;
while ( p ) {
if ( p->key > key )
p = p->left;
else if( p->key < key )
p = p->right;
else // (p->key == key)
return p;
} return p;
}
노드 삽입: insert 함수
15
null
4 20
17
19
2
15 4 20 17 19 2 32
32
16
노드 삽입: insert 함수
15
null
4 20
17
19
2
15 4 20 17 19 2 32
32
void insert( tree T, int key ) {
node v, p = T->root, prev;
while ( p ) {
prev = p;
if ( key < p->key )
p = p->left;
else p = p->right; }
v = createNode(key);
if ( T->root == null ) T->root = v;
else if ( key <= prev->key ) prev->left = v;
else prev->right = v;
v->parent = prev;
T->size ++;
}
16
16
노드 삭제: delete 함수
15
4 20
17
19
2 32
15
4 20
17 2 32
delete 19
노드 삭제: merging 방법에 의한 delete
15
4 20
17
19
2 32
15
4
17 2 32
delete 20
19
15
4 17
2
32
19
노드 삭제: merging 방법에 의한 delete
root
tmp
node
root
tmp
a
a b
b
Example 1
15
10 30
11
12
5 40
delete 15
20
height?
Example 2
15
10 30
4 7
5 40
delete 15
20
height?
노드 삭제: merging 방법에 의한 delete void deleteByMerging( tree T, node p ) {
node tmp, pt, new_root, a, b;
if ( p != null ) { a = p->left; b = p->right;
if ( T->root == p ) {
if ( p->left == null )
new_root = b;
else { // p has left child
new_root = tmp = a;
while ( tmp->right != null )
tmp = tmp->right;
tmp->right = b; }
T->root = new_root;
new_root->parent = null;
} (계속 … )
tmp
p = root
tmp
a
a b
b
no parent update here
노드 삭제: merging 방법에 의한 delete else { pt = p->parent;
if ( a == null ) {
if (pt->left == p) pt->left = b;
else pt->right = b;
b->parent = pt;
} else { // a != null
if (pt->left == p) pt->left = a;
else pt->right = a;
a->parent = pt;
tmp = a;
while ( tmp->right )
tmp = tmp->right;
tmp->right = b;
b->parent = tmp; }
} T->size --; } // END
root
tmp
p
root
tmp
a
a b
b
pt
노드 삭제: copying 방법에 의한 delete
15
4 20
17
19
2 32
delete 20
15
4 19
17
19
2 32 copy
15
4 19
17 2 32
노드 삭제: copying 방법에 의한 delete
root
tmp
node
a b
prev
root
tmp (copy key from tmp into node)
a b
prev
Example 1
15
10 30
11
12
5 40
delete 15
20
height?
Example 2
15
10 30
4 7
5 40
delete 15
20
height?
수행시간 • Search, insertion, deletion
– 트리 높이 h에 비례하는 시간이 걸림(왜?)
– h는 최대 얼마까지 증가할 수 있나?
– 그래서 세 함수의 수행시간은 모두 O( h ) = O( _____ ) 시간임
– 단점:
• 결국, 수행시간을 줄이기 위해선 트리의 높이를 최대한 작게 유지하는 것이 바람직함
– n개의 노드로 구성된 트리가 “균형잡혀 있다”는 것은 트리의 높이가 항상 O( log n )을 유지하고 있다면, 그 트리를 균형이진탐색트리(balanced binary search tree)라 부른다
– 당연히 균형이진탐색트리에서는 search, insertion, deletion은 모두 O( log n ) 시간이면 충분하다
– 균형이진탐색트리 예: red-black tree, AVL tree, splay tree, B-tree, etc.