80
검색 트리 Search Trees

Part4 search trees

Embed Size (px)

DESCRIPTION

search tree

Citation preview

Page 1: Part4 search trees

검색 트리 Search Trees

Page 2: Part4 search trees

Dynamic Set

• 여러 개의 키를 저장

• 다음과 같은 연산들을 지원하는 자료구조

• INSERT - 새로운 키의 삽입

• SEARCH - 키 탐색

• DELETE - 키의 삭제

• 예: 심볼 테이블

called Dynamic Set,

Dictionary,

or Search Structure

Spring 2012 Algorithms 2

Page 3: Part4 search trees

다양한 방법들

• 정렬된 혹은 정렬되지 않은 배열 혹은 연결 리스트를 사용할 경우 INSERT, SEARCH, DELETE 중 적어도 하나는 O(n).

• 이진탐색트리(Binary Search Tree), 레드-블랙 트리, AVL-트리 등의 트리에 기반한 구조들

• Direct Address Table, 해쉬 테이블 등

Spring 2012 Algorithms 3

Page 4: Part4 search trees

탐색 트리

• Dynamic set을 트리의 형태로 구현

• 일반적으로 SEARCH, INSERT, DELETE연산이 트리의 높이(height)에 비례하는 시간복잡도를 가짐

• 이진검색트리(Binary Search Tree), 레드-블랙 트리(red-black tree), B-트리 등

Spring 2012 Algorithms 4

Page 5: Part4 search trees

이진검색트리 (BST)

• 이진 트리이면서

• 각 노드에 하나의 키를 저장

• 각 노드 v에 대해서 그 노드의 왼쪽 부트리(subtree)에 있는 키들은 key[v]보다 작거나 같고, 오른쪽 부트리에 있는 값은 크거나 같다.

Spring 2012 Algorithms 5

Page 6: Part4 search trees

이진검색트리 (BST)

BST의 예

Spring 2012 Algorithms 6

Page 7: Part4 search trees

이진검색트리의 표현

• 연결구조(Linked Structure) 표현

left key p right

node

left key p right left key p right

각 노드는 하나의 키(key)와 왼쪽자식(left), 오른쪽 자식(right), 그리고 부모노드(p)의 주소를 저장

Spring 2012 Algorithms 7

Page 8: Part4 search trees

BST의 Inorder-순회

1. 먼저 TL을 inorder로 순회하고,

2. r을 순회하고,

3. TR을 inorder로 순회.

이진트리를 루트노드 r, 왼쪽 부트리 TL, 오른쪽 부트리

TR로 나누어 생각

r

TL TR

Spring 2012 Algorithms 8

Page 9: Part4 search trees

BST의 Inorder-순회

2, 3, 5, 5, 7, 8순으로 순회

2, 3, 5, 5, 7, 8

BST의 Inorder순회는 key값들을 크기순으로 정렬

Spring 2012 Algorithms 9

Page 10: Part4 search trees

BST의 Inorder-순회

시간복잡도 O(n)

Spring 2012 Algorithms 10

Page 11: Part4 search trees

Postorder와 Preorder순회

PREORDER-TREE-WALK(x)

if x ≠ NIL

then print key[x]

PRE-ORDER-TREE-WALK(left[x])

PRE-ORDER-TREE-WALK(right[x]).

POSTORDER-TREE-WALK(x)

if x ≠ NIL

then POST-ORDER-TREE-WALK(left[x])

POST-ORDER-TREE-WALK(right[x]).

print key[x] Spring 2012 Algorithms 11

Page 12: Part4 search trees

SEARCH

키 13을 검색: 15 → 6 → 7 → 13

Spring 2012 Algorithms 12

Page 13: Part4 search trees

SEARCH

시간복잡도: O(h), 여기서 h는 트리의 높이

Spring 2012 Algorithms 13

Page 14: Part4 search trees

SEARCH - Iterative Version

시간복잡도: O(h), 여기서 h는 트리의 높이

Spring 2012 Algorithms 14

Page 15: Part4 search trees

최소값

최소값은 항상 가장 왼쪽 노드에 존재

시간복잡도: O(h)

Spring 2012 Algorithms 15

Page 16: Part4 search trees

최대값

최대값은 항상 가장 오른쪽 노드에 존재

시간복잡도: O(h)

Spring 2012 Algorithms 16

Page 17: Part4 search trees

Successor

• 노드 x의 successor란 key[x]보다 크면서 가장 작은 키를 가진 노드

• 모든 키들이 서로 다르다고 가정

15

6

3

2 4

7

13

9

18

17 20

15의 successor는 17 6의 successor는 7 4의 successor는 6

Spring 2012 Algorithms 17

Page 18: Part4 search trees

Successor

• 3가지 경우

• 노드 x의 오른쪽 부트리가 존재할 경우, 오른쪽 부트리의 최소값.

• 오른쪽 부트리가 없는 경우, 어떤 노드 y의 왼쪽 부트리의 최대값이 x가 되는 그런 노드 y가 x의 successor

• 부모를 따라 루트까지 올라가면서 처음으로 누군가의 왼쪽 자식이 되는 노드

• 그런 노드 y가 존재하지 않을 경우 successor가 존재하지 않음 (즉, x가 최대값)

Spring 2012 Algorithms 18

Page 19: Part4 search trees

Successor

시간복잡도: O(h)

Spring 2012 Algorithms 19

Page 20: Part4 search trees

Predecessor

• 노드 x의 predecessor란 key[x]보다 작으면서 가장 큰 키를 가진 노드

• Successor와 반대

Spring 2012 Algorithms 20

Page 21: Part4 search trees

INSERT

15

6

3

2 4

7

13

9

18

17 20

14

14를 insert

x=NIL

y

2개의 포인터 x, y를 사용

Spring 2012 Algorithms 21

Page 22: Part4 search trees

30

40 20

25 10 35

30 30

20

30

20

25

30

40 20

25

30

40 20

25 10

(a) (b) (c) (d)

(e) (f)

INSERT

Page 23: Part4 search trees

INSERT

시간복잡도: O(h) Spring 2012 Algorithms 23

Page 24: Part4 search trees

INSERT: Recursive Version

treeInsert(t, x)

{

if (t=NIL) then {

key[r] ← x; ▷ r : 새 노드

return r;

}

if (x < key(t))

then {left[t] ← treeInsert(left[t], x); return t;}

else {right[t] ← treeInsert(right[t], x); return t;}

}

t : 트리의 루트 노드 x : 삽입하고자 하는 키

Spring 2012 Algorithms 24

Page 25: Part4 search trees

DELETE

• Case 1: 자식노드가 없는 경우

15

6

3

2 4

7

13

9

18

17 20

4를 삭제하는 경우: 그냥 삭제

Spring 2012 Algorithms 25

Page 26: Part4 search trees

55

28 8

60 15

90

48

30 18

38

3

50

r

(a) r의 자식이 없음 (b) 단순히 r을 제거한다

36 32

33

55

28 8

60 15

90

48

30

38

3

50

36 32

33

삭제의 예: Case 1

Page 27: Part4 search trees

DELETE

• Case 2: 자식노드가 1개인 경우

7을 삭제하는 경우: 자신의 자식노드를 원래 자신의 위치로

15

6

3

2 4

7

13

9

18

17 20

Spring 2012 Algorithms 27

Page 28: Part4 search trees

55

28 8

60 15

90

48

30 18

38

3

50

r

(a) r의 자식이 하나뿐임

55

28 8

60 15

90

48 18 3

50

(c) r 자리에 r의 자식을 놓는다

36 32

33

38

36 32

33

55

28 8

60 15

90

48

18

38

3

50

(b) r을 제거

36 32

33

삭제의 예: Case 2

Page 29: Part4 search trees

DELETE

• Case 3: 자식노드가 2개인 경우

13을 삭제하는 경우 13

6

3

2 4

7

15

16

18

17 20

삭제하려는 노드의 successor

삭제하려는 노드의 successor는 최대 1개의 자식노드를 가짐

Spring 2012 Algorithms 29

Page 30: Part4 search trees

DELETE

• Case 3: 자식노드가 2개인 경우

13을 삭제하는 경우 15

6

3

2 4

7

15

16

18

17 20

2. Successor 노드를 대신 삭제한다 (Case 1 or 2에 해당)

1. successor의 값을 삭제하려는 노드로 copy한다.

Spring 2012 Algorithms 30

Page 31: Part4 search trees

55

28 8

60 15

90

48

30

45 18

41

38

3

50

r

s

(a) r의 직후원소 s를 찾는다

36 32

33

55

30

8

60 15

90

48

45 18

41

38

3

50 s

(b) r을 없앤다

36 32

33

삭제의 예: Case 3

Page 32: Part4 search trees

55

30 8

60 15

90

48

45 18

41

3

50

s

(d) s가 있던 자리에 s의 자식을 놓는다

38

36 32

33

55

30 8

60 15

90

48

45 18

41

38

3

50

s

(c) s를 r자리로 옮긴다

36 32

33

Page 33: Part4 search trees

시간복잡도: O(h)

Spring 2012 Algorithms 33

Page 34: Part4 search trees

Spring 2012 Algorithms 34

Page 35: Part4 search trees

BST

• 각종 연산의 시간복잡도 O(h)

• 그러나, 최악의 경우 트리의 높이 h=O(n)

• 균형잡힌(balanced) 트리

• 레드-블랙 트리 등

• 키의 삽입이나 삭제시 추가로 트리의 균형을 잡아줌으로써 높이를 O(log2n)으로 유지

Spring 2012 Algorithms 35

Page 36: Part4 search trees

레드-블랙 트리

• 이진탐색트리의 일종

• 균형잡힌 트리: 높이가 O(log2n)

• SEARCH, INSERT, DELETE 연산을 최악의 경우에도 O(log2n) 시간에 지원

Spring 2012 Algorithms 36

Page 37: Part4 search trees

레드-블랙 트리

• 각 노드는 하나의 키(key), 왼쪽자식(left), 오른쪽 자식(right),

그리고 부모노드(p)의 주소를 저장

• 자식노드가 존재하지 않을 경우 NIL 노드라고 부르는 특수한 노드가

있다고 가정

• 따라서 모든 리프노드는 NIL노드

• 루트의 부모도 NIL노드라고 가정

• 노드들은 내부노드와 NIL노드로 분류

Spring 2012 Algorithms 37

Page 38: Part4 search trees

레드-블랙 트리

Spring 2012 Algorithms 38

Page 39: Part4 search trees

레드-블랙 트리: 정의

• 다음의 조건을 만족하는이진탐색트리:

1. 각 노드는 red 혹은 black이고,

2. 루트노드는 black이고,

3. 모든 리프노드(즉, NIL노드)는 블랙이고,

4. 레드노드의 자식노드들은 전부 블랙이고(즉, 레드노드는 연속되어 등장하지 않고),

5. 모든 노드에 대해서 그 노드로부터 자손인 리프노드에 이르는 모든 경로에는 동일한 개수의 블랙노드가 존재한다.

Spring 2012 Algorithms 39

Page 40: Part4 search trees

레드-블랙 트리: 예

15

6

3

4

7

13

NIL

18

h=4 bh=2

h=1 bh=1

h=3 bh=2

h=2 bh=1

h=2 bh=1

h=1 bh=1

h=1 bh=1

Spring 2012 Algorithms 40

Page 41: Part4 search trees

레드-블랙 트리의 높이

• 노드 x의 높이 h(x)는 자신으로부터 리프노드까지의 가장 긴 경로에 포함된 에지의 개수이다.

• 노드 x의 블랙-높이 bh(x)는 x로부터 리프노드까지의 경로상의 블랙노드의 개수이다 (노드 x 자신은 불포함)

Spring 2012 Algorithms 41

Page 42: Part4 search trees

레드-블랙 트리의 높이

• 높이가 h인 노드의 블랙-높이는 bh≥h/2 이다.

• 조건4에 의해 레드노드는 연속될수 없으므로 당연

• 노드 x를 루트로하는 임의의 부트리는 적어도 2bh(x)-1개의 내부노드를 포함한다(수학적귀납법)

• n개의 내부노드를 가지는 레드블랙트리의 높이는 2log2(n+1)이하이다.

• n≥2bh-1≥2h/2-1 이므로

Spring 2012 Algorithms 42

Page 43: Part4 search trees

Left and Right Rotation

• 시간복잡도 O(1)

• 이진탐색트리의 특성을 유지

Spring 2012 Algorithms 43

Page 44: Part4 search trees

Left Rotation

• y = right[x] ≠NIL이라고 가정

• 루트노드의 부모도 NIL이라고 가정

Spring 2012 Algorithms 44

Page 45: Part4 search trees

Left Rotation

Spring 2012 Algorithms 45

Page 46: Part4 search trees

INSERT

• 보통의 BST에서처럼 노드를 INSERT한다.

• 새로운 노드 z를 red노드로 한다.

• RB-INSERT-FIXUP을 호출한다.

Spring 2012 Algorithms 46

Page 47: Part4 search trees

RB-INSERT-FIXUP

• 위반될 가능성이 있는 조건들

1. OK.

2. 만약 z가 루트노드라면 위반, 아니라면 OK.

3. OK.

4. z의 부모 p[z]가 red이면 위반.

5. OK.

Spring 2012 Algorithms 47

Page 48: Part4 search trees

RB-INSERT-FIXUP

• Loop Invariant:

• z는 red노드

• 오직 하나의 위반만이 존재한다:

• 조건2: z가 루트노드이면서 red이거나, 또는

• 조건4: z와 그 부모 p[z]가 둘 다 red이거나.

• 종료조건:

• 부모노드 p[z]가 black이되면 종료한다. 만약 종료 후 조건2가 위반일 경우 z를 블랙으로 바꿔주면 해결된다.

Spring 2012 Algorithms 48

Page 49: Part4 search trees

경우1: z의 삼촌이 red

조건 2와 4 이외의 조건들은 여전히 OK면서 z가 두칸 위로 올라감

왜 z의 할아버지가

반드시 존재할까?

왜 z의 할아버지가

반드시 존재할까?

Spring 2012 Algorithms 49

Page 50: Part4 search trees

경우2와 3: z의 삼촌이 black

• 경우2: z가 오른쪽 자식인 경우

• p[z]에 대해서 left-rotation한 후 원재 p[z]를 z로

• 경우3으로

• 경우3: z가 왼쪽 자식인 경우

• p[z]를 black, p[p[z]]를 red로 바꿈

• p[p[z]]에 대해서 right-rotation

Spring 2012 Algorithms 50

Page 51: Part4 search trees

경우 4,5,6

• 경우 1,2,3은 p[z]가 p[p[z]]의 왼쪽자식인 경우들

• 경우 4,5,6은 p[z]가 p[p[z]]의 오른쪽 자식인 경우

• 경우 1,2,3과 대칭적이므로 생략

Spring 2012 Algorithms 51

Page 52: Part4 search trees

Spring 2012 Algorithms 52

Page 53: Part4 search trees

INSERT의 시간복잡도

• BST에서의 INSERT: O(log2n)

• RB-INSERT-FIXUP

• 경우1에 해당할 경우 z가 2레벨 상승

• 경우 2,3에 해당할 경우 O(1)

• 따라서 트리의 높이에 비례하는 시간

• 즉, INSERT의 시간복잡도는 O(log2n)

Spring 2012 Algorithms 53

Page 54: Part4 search trees

Spring 2012 Algorithms 54

Page 55: Part4 search trees

DELETE

• 보통의 BST에서처럼 DELETE한다.

• 실제로 삭제된 노드 y가 red였으면 종료.

• y가 black이었을 경우RB-DELETE-FIXUP을 호출한다.

여기서 x는 y가 자식이 있었을 경우 그 자식노드, 없었을 경우 NIL노드.

두 경우 모두 p[x]는 원래 p[y]였던 노드

Spring 2012 Algorithms 55

Page 56: Part4 search trees

RB-DELETE-FIXUP(T,x)

1. OK.

2. y가 루트였고 x가 red인 경우 위반

3. OK.

4. p[y]와 x가 모두 red일 경우 위반

5. 원래 y를 포함했던 모든 경로는 이제 black노드가 하나 부족

• 노드 x에 “extra black”을 부여해서 일단 조건5를 만족

• 노드 x는 “double black” 혹은 “red & black”

Spring 2012 Algorithms 56

Page 57: Part4 search trees

RB-DELETE-FIXUP(T,x)

• 아이디어:

• extra black을 트리의 위쪽으로 올려보냄

• x가 red&black상태가 되면 그냥 black노드로 만들고 끝냄

• x가 루트가 되면 그냥 extra black을 제거

• Loop Invariant

• x는 루트가 아닌 double-black노드

• w는 x의 형제노드

• w는 NIL 노드가 될수 없음 (아니면 x의 부모에 대해 조건5가 위반)

Spring 2012 Algorithms 57

Page 58: Part4 search trees

경우1: w가 red인 경우

• w의 자식들은 black

• w를 black으로, p[x]를 red로

• p[x]에 대해서 left-rotation적용

• x의 새로운 형제노드는 원래 w의 자식노드, 따라서 black노드

• 경우 2,3,혹은 4에 해당

double

black

double

black

black black

black

≠ NIL node (조건5)

Spring 2012 Algorithms 58

Page 59: Part4 search trees

경우2: w는 black, w의 자식들도 black

• x의 extra-black을 뺏고, w를 red로 바꿈.

• p[x]에게 뺏은 extra-black을 준다.

• p[x]를 새로운 x로 해서 계속.

• 만약 경우1에서 이 경우에 도달했다면 p[x]는 red였고, 따라서 새로운 x는 red&black이 되어서 종료

gray노드는 unknown

color

Spring 2012 Algorithms 59

Page 60: Part4 search trees

경우3: w는 black, w의 왼쪽자식이 red

• w를 red로, w의 왼자식을 black으로

• w에 대해서 right-rotation적용

• x의 새로운 형제 w는 오른자식이 red: 경우4에 해당

Spring 2012 Algorithms 60

Page 61: Part4 search trees

경우4: w는 black, w의 오른쪽자식이 red

• w의 색을 현재 p[x]의 색으로 (unknown color)

• p[x]를 black으로, w의 오른자식을 black으로

• p[x]에 대해서 left-rotation적용

• x의 extra-black을 제거하고 종료

Spring 2012 Algorithms 61

Page 62: Part4 search trees

경우 5,6,7,8

• 경우 1,2,3,4는 x가 왼쪽 자식인 경우

• 경우 5,6,7,8은 x가 p[x]의 오른쪽 자식인 경우

• 경우 1,2,3,4와 각각 대칭적임

Spring 2012 Algorithms 62

Page 63: Part4 search trees

Spring 2012 Algorithms 63

Page 64: Part4 search trees

Spring 2012 Algorithms 64

Page 65: Part4 search trees

시간복잡도

• BST에서의 DELETE: O(log2n)

• RB-DELETE-FIXUP: O(log2n)

Spring 2012 Algorithms 65

Page 66: Part4 search trees

B-Trees

• 디스크의 접근 단위는 블록(페이지)

• 디스크에 한 번 접근하는 시간은 수십만 명령어의 처리 시간과 맞먹는다.

• 검색트리가 디스크에 저장되어 있다면 트리의 높이를 최소화하는 것이 유리하다.

• B-트리는 다진검색트리가 균형을 유지하도록 하여 최악의 경우 디스크 접근 횟수를 줄인 것이다.

Spring 2012 Algorithms 66

Page 67: Part4 search trees

T0

key0 key1 key2 … keyk-1

T1 Tk T2 T3

Ti keyi-1 < < keyi

다진검색트리

Spring 2012 Algorithms 67

Page 68: Part4 search trees

B-Tree

B-Tree는 균형잡힌 다진검색트리로 다음의 성질을 만족한다

루트를 제외한 모든 노드는 k/2 ~ k 개의 키를 갖는다. 이때 k를 B-

트리의 차수(order)라고 부른다.

모든 리프 노드는 같은 깊이를 가진다.

Spring 2012 Algorithms 68

Page 69: Part4 search trees

<key0, p0> <key1, p1> … <keyk-1, pk-

1>

부모 노드의 페이지

B-트리의 노드 구조

Spring 2012 Algorithms 69

Page 70: Part4 search trees

<key0, p0> … <keyi, pi> …

페이지 pi

키 keyi를 가진 record

B-트리를 통해 Record에 접근하는 과정

Spring 2012 Algorithms 70

Page 71: Part4 search trees

B-Tree에서의 삽입

BTreeInsert(t, x) { x를 삽입할 리프 노드 r을 찾는다; x를 r에 삽입한다;

if (r에 오버플로우 발생) then clearOverflow(r);

} clearOverflow(r) { if (r의 형제 노드 중 여유가 있는 노드가 있음) then {r의 남는 키를 넘긴다}; else { r을 둘로 분할하고 가운데 키를 부모 노드로 넘긴다; if (부모 노드 p에 오버플로우 발생) then clearOverflow(p); } }

▷ t : 트리의 루트 노드 ▷ x : 삽입하고자 하는 키

Spring 2012 Algorithms 71

Page 72: Part4 search trees

1 2 3 4 6 8 10 15 17 19 20

7 13 25 34 (a)

37 38 40 41 45 27 28 30 33

1 2 3 4 6 8 9 10 15 17 19 20

7 13 25 34 (b)

37 38 40 41 45 27 28 30 31 33

9, 31 삽입

5 삽입

B-Tree에서 삽입의 예

Spring 2012 Algorithms 72

Page 73: Part4 search trees

1 2 3 4 5 6 8 9 10 15 17 19 20

7 13 25 34 (c)

37 38 40 41 45 27 28 30 31 33

오버플로우!

1 2 3 4 5 7 8 9 10 15 17 19 20

6 13 25 34

37 38 40 41 45 27 28 30 31 33

39 삽입

Spring 2012 Algorithms 73

Page 74: Part4 search trees

1 2 3 4 5 7 8 9 10 15 17 19 20

6 13 25 34

37 38 39 40 41 45 27 28 30 31 33

오버플로우!

39 삽입 (d)

1 2 3 4 5 7 8 9 10 15 17 19 20

6 13 25 34 40

37 38 39 27 28 30 31 33 41 45

분할! 23, 35, 36 삽입

Spring 2012 Algorithms 74

Page 75: Part4 search trees

23, 35, 36 삽입

1 2 3 4 5 7 8 9 10 15 17 19 20 23

6 13 25 34 40

35 36 37 38 39 27 28 30 31 33 41 45

32 삽입

(e)

Spring 2012 Algorithms 75

Page 76: Part4 search trees

1 2 3 4 5 7 8 9 10 15 17 19 20 23

6 13 25 31 34 40

35 36 37 38 39 27 28 30 41 45 32 33

오버플로우!

1 2 3 4 5 7 8 9 10 15 17 19 20 23

6 13 25

35 36 37 38 39 27 28 30 41 45 32 33

분할!

34 40

31

32 삽입

1 2 3 4 5 7 8 9 10 15 17 19 20 23 35 36 37 38 39 41 45

오버플로우!

(f)

6 13 25 34 40

27 28 30 31 32 33

분할!

Spring 2012 Algorithms 76

Page 77: Part4 search trees

B-Tree에서의 삭제

BTreeDelete(t, x, v) { if (v가 리프 노드 아님) then { x의 직후원소 y를 가진 리프 노드를 찾는다; x와 y를 맞바꾼다; } 리프 노드에서 x를 제거하고 이 리프 노드를 r이라 한다; if (r에서 언더플로우 발생) then clearUnderflow(r); } clearUnderflow(r) { if ( r의 형제 노드 중 키를 하나 내놓을 수 있는 여분을 가진 노드가 있음) then { r이 키를 넘겨받는다;} else { r의 형제 노드와 r을 합병한다; if (부모 노드 p에 언더플로우 발생) then clearUnderflow(p); } }

▷ t : 트리의 루트 노드

▷ x : 삭제하고자 하는 키

▷ v : x를 갖고 있는 노드

Spring 2012 Algorithms 77

Page 78: Part4 search trees

15

1 2 3 5 6 7 9 10 16 18 24 25 26 20 21

19 22 4 8

7 삭제

(a)

(b) 15

1 2 3 5 6 9 10 16 18 24 25 26 20 21

19 22 4 8

4 삭제

B-Tree에서 삭제의 예

Spring 2012 Algorithms 78

Page 79: Part4 search trees

15

1 2 3 6 9 10 16 18 24 25 26 20 21

19 22 5 8

언더플로우! 15

1 2 5 6 9 10 16 18 24 25 26 20 21

19 22 3 8

9 삭제

(c) 15

1 2 3 4 6 9 10 16 18 24 25 26 20 21

19 22 5 8

4 제거

4, 5 교환

재분배

Spring 2012 Algorithms 79

Page 80: Part4 search trees

15

1 2 5 6 10 16 18 24 25 26 20 21

19 22 3 8

(d)

언더플로우!

15

1 2 5 6 8 10 16 18 24 25 26 20 21

19 22 3

언더플로우!

병합!

1 2 5 6 8 10 16 18 24 25 26 20 21

3 15 19 22

병합!

Spring 2012 Algorithms 80