당신은 주제를 찾고 있습니까 “최적 이진 탐색 트리 – 최적이진탐색트리(OBST 설명), optimal binary search tree“? 다음 카테고리의 웹사이트 you.future-user.com 에서 귀하의 모든 질문에 답변해 드립니다: https://you.future-user.com/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 스티브쌤 TV with JJ-정보컴퓨터,정컴,전산직 이(가) 작성한 기사에는 조회수 2,131회 및 좋아요 13개 개의 좋아요가 있습니다.
Table of Contents
최적 이진 탐색 트리 주제에 대한 동영상 보기
여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!
d여기에서 최적이진탐색트리(OBST 설명), optimal binary search tree – 최적 이진 탐색 트리 주제에 대한 세부정보를 참조하세요
2021.01.01부터 Steve TV 채널을 제제아뜰에서 운영합니다.
영상의 제공정책이 일부 변경될 수 있습니다. 모든 자료는 카페에 업로드 되어 있습니다.
카페이동: http://cafe.daum.net/inforedu
구독하기: https://bit.ly/39pXyfg
#정보컴퓨터임용, #정컴임용, #정컴기출
최적 이진 탐색 트리 주제에 대한 자세한 내용은 여기를 참조하세요.
최적 이진 탐색 트리 (Optimal Binary Search Tree)
최적 이진 탐색 트리 (Optimal Binary Search Tree). 메시에 2019. 6. 16. 02:15. 이전 포스팅에서 설명했던 이진 탐색 트리 (BST) 의 활용 예를 보자.
Source: gsmesie692.tistory.com
Date Published: 10/13/2022
View: 9487
[알고리즘] 최적 이진 검색 트리, Optimal Binary Search Trees
이진 검색 트리는 말 그대로 이진 트리를 검색 목적으로 사용하는 것이다. 왼쪽에는 같거나 더 작은 값을, 오른쪽에는 더 큰 값을 저장하고 leaf 노드들 …
Source: nolzaheo.tistory.com
Date Published: 11/16/2022
View: 2712
#5 최적 이진 탐색 트리(Optimal Binary Search Trees)
최적 이진 탐색 트리란 , 평균 탐색하는 횟수를 최소로 만드는 이진 탐색 트리를 말한다. (그냥 탐색 횟수가 아니라 평균 탐색 횟수로 구하는 이유는 확률 …
Source: cometouniverse.tistory.com
Date Published: 4/30/2022
View: 2419
Optimal Binary Search Tree – Fake it till you make it
최적 이진 탐색트리 문제. : 트리의 각 노드가 탐색될 확률이 주어질 때, 그 트리의 평균 비교횟수가 최소인 탐색 트리를 구축하는 것이 목적이다.
Source: woochan-autobiography.tistory.com
Date Published: 1/5/2022
View: 4727
최적 이진검색트리 – velog
Binary Search Tree는 다들 한번쯤 봤을법한 검색트리기법중 하나이다. 이번 알고리즘은 이 이진검색트리에서 평균 검색비용을 최적화하는 알고리즘을 …
Source: velog.io
Date Published: 2/20/2022
View: 2943
알고리즘 #9_ 최적 이진 검색 트리(BST: Binary Search Tree)
추가적으로, 우리는 어떤 단어 K에 대해서 탐색이 되지 않을 경우도 고려해야 합니다. 따라서 가상키라는 개념을 통해 이를 해결합니다. 가상키는 이진 …
Source: doorbw.tistory.com
Date Published: 7/6/2021
View: 7025
주제와 관련된 이미지 최적 이진 탐색 트리
주제와 관련된 더 많은 사진을 참조하십시오 최적이진탐색트리(OBST 설명), optimal binary search tree. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

주제에 대한 기사 평가 최적 이진 탐색 트리
- Author: 스티브쌤 TV with JJ-정보컴퓨터,정컴,전산직
- Views: 조회수 2,131회
- Likes: 좋아요 13개
- Date Published: 2019. 12. 3.
- Video Url link: https://www.youtube.com/watch?v=D9PNAFnAXHc
최적 이진 탐색 트리 (Optimal Binary Search Tree)
이전 포스팅에서 설명했던 이진 탐색 트리 (BST) 의 활용 예를 보자. 설명할 때는 보통 이해하기 쉽게 노드에 들어있는 데이터를 숫자로 가정하지만, 실제로 쓰일 때는 문자열이라던가 더 다양한 데이터가 들어갈 수 있다. 예를 들어 주소록에서 어떤 사람 이름을 검색하기 위해 BST를 만들었다고 치자.
보면 알겠지만 여기서는 크다, 작다의 기준은 알파벳 ABC순 정렬이다. B로 시작하는 단어가 C로 시작하는 단어보다 왼쪽에 위치하게 되는 것이다.
서로 다른 모양의 트리 2개를 그려놨는데 둘 다 BST다. 그러니까 같은 데이터셋을 가지고 만들 수 있는 BST의 모양은 유일하지 않다. 이 두 BST의 차이는 무엇일까? BST에서 검색을 할 때는 루트 노드부터 시작해서 재귀함수를 호출하면서 아래로 내려가기 때문에, 검색할 대상이 아래쪽에 있을수록 함수 호출을 해야 하는 횟수가 늘어난다. 예를 들어 ‘Crystal’ 을 검색한다고 하면 왼쪽 BST에서는 바로 결과가 나오지만 오른쪽 BST에서는 3번 더 내려가야 한다. 그렇다면 다른 제약사항이 없다고 했을 때 일반적으로 생각할 수 있는건 BST를 최대한 적은 층수 (레벨) 로 구성하는 게 좋다고 생각할 수 있다.
다만 현실에서는 여기에 제약사항이 더 붙는다. 이를테면 단어별로 검색 요청이 들어오는 빈도가 다른데, John은 영어에서 아주 흔한 이름이므로 검색 빈도가 높을 것이라고 생각할 수 있다. 단어별로 검색 빈도가 아래와 같다고 가정하자.
Crystal = 0.1 / Daisy = 0.2 / Beatrice = 0.3 / John = 0.4
BST의 ‘평균 검색 시간’ 은 단어별 ‘검색 빈도 * 필요 탐색 횟수’ 를 모두 더한 것이라고 정의한다. 식으로 표현하면 다음과 같다. c는 단어를 검색하는데 필요한 함수 호출 횟수, p는 단어의 검색 빈도, n은 단어의 수를 의미한다.
위 예시의 두 BST에 대해서 이걸 계산해보면,
왼쪽: (0.1*1) + (0.2*2) + (0.3*2) + (0.4*3) = 2.3
오른쪽: (0.1*4) + (0.2*3) + (0.3*2) + (0.4*1) = 2.0
으로 오른쪽 BST가 더 효율이 좋다는 것을 알 수 있다. 직관적으로 표현하면 검색 빈도가 높은 단어가 깊은 곳에 박혀있으면 효율이 떨어지고, 반대로 루트 노드와 가까운 곳에 있으면 효율이 좋다는 얘기다. 오른쪽 BST가 트리의 레벨은 1 더 높지만, 제일 검색 빈도가 낮은 Crystal을 아래로 내리고 검색 빈도가 높은 John을 루트 노드로 놓으니 오히려 효율이 더 좋아졌다.
가능한 BST의 모양들 중에서 평균 검색 시간이 제일 낮은, 가장 효율적인 트리를 최적 이진 탐색 트리 (Optimal BST) 라고 부른다. 그럼 단어들이 주어졌을 때 최적 BST를 어떻게 찾아낼까?
가능한 모든 BST의 모양을 만들어보는 건 너무 비효율적이다. 노드 n개가 있고 어떤 노드를 루트에 뒀을 때, 그 노드를 제외한 나머지 n-1개의 모든 노드들은 부모 노드의 왼쪽이나 오른쪽에 위치할 수 있으므로 가능한 BST의 경우의 수가 2^(n-1) 개이다. 즉 지수 시간복잡도라는 얘기다.
그래서 최적 BST를 빨리 찾기 위해서 또 다이나믹 프로그래밍이 등장한다. BST의 특성상 어떤 BST의 왼쪽, 오른쪽 서브트리가 각각 최적 BST여야 해당 BST도 최적이다. 즉 최적의 원리가 성립한다.
위 그림을 보자. 어떤 BST가 1번째 key (단어) 가 루트라는 제약사항을 가진 최적 BST라고 하자. 왼쪽, 오른쪽 서브트리는 각각 최적 BST이고, 전체 BST에서 단어를 찾을 때 걸리는 평균 검색 시간은 서브트리에서 찾는 시간 + 루트노드를 탐색하는 시간이다.
이걸 식으로 세워보자.
먼저 i번째 key부터 j번째 key까지로 최적 BST를 만들었을 때의 평균 검색 시간, 즉 최적값을 A[i][j] 라고 정의하자. 그러면 서브트리의 평균 검색 시간은 루트노드가 k번째 key일 때 왼쪽, 오른쪽 각각 A[1][k-1], A[k+1][n] 이다 (서브트리는 각각 최적 BST이므로). 그리고 루트노드는 깊이가 1이므로
에서 c를 뺀 (c=1) 것이 루트노드를 탐색하는 시간이다.
그리고 k개의 BST 중 하나는 반드시 최적이다. 서브트리들은 이미 최적이라고 했기 때문에 루트노드를 k번 바꿔보고 그 중 최적의 값을 구하면 그게 전체에 대한 최적의 값이다. 이를 종합하면 아래와 같은 식이 나온다.
1부터 n까지가 아니라 i번째부터 j번째까지의 key로 일반화할 수도 있다. 그러면 아래와 같은 식이 된다.
이 식을 이용해서 A라는 2차원 배열을 채워나가서, A[1][n] 의 값을 얻으면 그것이 최적 BST의 평균 검색 시간 (최적값) 이 된다.
다만 A라는 DP 배열 하나만으로는 최적값은 구할 수 있지만 최적 BST의 모양을 알 수가 없다. 최적 BST를 구성하기 위한 아이디어는 R이라는 2차원 배열을 하나 더 만드는 것이다. 여기서 R의 각 칸에 들어가는 값은 A 배열에 최적값을 넣는 순간의 k값으로, 이는 즉 i번째 key부터 j번째 key까지를 이용해 BST를 만들 때 루트가 되는 노드의 번호를 의미한다. 즉 R[1][n] 을 구하면 최적 BST의 루트노드를 구할 수 있다. 그 다음 레벨의 노드부터는? 루트가 된 노드가 k번 노드라고 치면 그 왼쪽 서브트리의 루트노드 (즉 k번 노드의 left child) 는 R[1][k-1], 오른쪽 서브트리의 루트노드는 R[k+1][n] 이 된다. 이런 식으로 R 배열의 값들을 이용해 재귀함수를 호출해주면서 노드를 만들어나가면 최적 BST가 만들어진다.
예시를 보면서 이해해보자. 4개의 key (단어) 들이 있고 각각의 검색 빈도는 왼쪽과 같다. A 배열이든 R 배열이든 ‘i번째부터 j번째 key를 이용해서 만든 최적 BST’ 에 대한 내용을 담고 있으므로, i<=j인 경우만 생각하면 된다. 그러므로 대각선을 기준으로 왼쪽 아래에는 값을 넣을 필요가 없고, 대각선 칸은 0으로 모두 채운다. i=j인 경우는 하나의 단어, 그러니까 노드 하나뿐인 BST가 되므로 A 배열에는 그 단어의 검색 빈도가 그대로 들어가고 R 배열에는 그 단어의 번호가 들어간다. 그 다음 칸부터 본격적으로 위의 점화식을 이용해서 칸을 채운다. 예를 들어 A[1][2] 의 경우, A[1][0] + A[2][2] (k=1인 경우) A[1][1] + A[3][2] (k=2인 경우) 둘 중에 작은 값을 선택하게 되는데 둘 다 3/8이고, 거기에 각 key의 검색 빈도를 다 더하므로 3/8이 두번 더 더해져서 9/8이 된다. R[1][2] 에는 선택한 작은 값에 해당하는 k값을 넣는데 여기서는 1, 2를 둘 다 넣을 수 있지만 동률일 경우 더 작은 값을 우선으로 넣기로 한다. A, R 배열을 만드는 파이썬 함수를 작성했다. 신경쓰일 만한 부분은 주석으로도 달아놨지만 한번 더 써보면, - n은 key의 개수, p는 각 key에 대한 검색 빈도가 저장되어 있는 리스트다. - 아까 위에서 봤던 예시 그림에서 A, R 배열을 잘 보면 가로로는 0, 1, 2... 인데 세로로는 1, 2, 3... 이다. 그러니까 코드를 좀 더 이해하기 쉽게 작성하기 위해서 세로로 한 줄을 더 만들었다. 위 그림이랑 비교해서 제일 위에 0으로 채워진 한 줄이 더 있는 것이다. 메모리 낭비라고 생각할 수 있지만 예시니까 넘어가자 - for문 두 개와 diagonal 변수는 대각선 기준으로 위쪽만 돌기 위해 저렇게 만들었다. - 그 아래로는 점화식을 코드로 옮긴 것이다. 첫번째 for문은 minimum 찾는 부분, 두번째 for문은 p값들을 더하는 시그마 부분이다. 위에서 만든 R 리스트를 이용해서 최적 BST를 만드는 함수다. 아까 R 배열에 대해서 설명할 때 언급했듯 재귀적으로 동작하므로 i, j를 인자로 받아야 한다. 예시처럼 key가 4개라면, 처음 호출할 때는 (1, 4, R, Keys) 로 호출하면 된다. Keys는 말 그대로 key 단어들이 들어가있는 리스트다. R 리스트에서 k를 가져온 다음, k가 0이 아니라면 k번째 key를 사용해서 노드를 만든다. 그리고 이 노드의 왼쪽, 오른쪽 자식노드를 각각 재귀호출로 만든다. 마지막에 return node를 해줘야 만들어진 노드 객체가 부모 노드의 left, right 속성으로 들어간다는 점을 주의하자.
[알고리즘] 최적 이진 검색 트리, Optimal Binary Search Trees
최적 이진 검색 트리란?
최적 이진 검색트리의 뜻을 알기위해서는 먼저 이진 검색 트리의 뜻을 알아야한다. 이진 검색 트리는 말 그대로 이진 트리를 검색 목적으로 사용하는 것이다. 왼쪽에는 같거나 더 작은 값을, 오른쪽에는 더 큰 값을 저장하고 leaf 노드들 간의 depth 차이가 1보다 클 수 없다. 여기서 ‘최적’이란 단어까지 붙으면 최적 이진 검색트리가 된다. 최적 이진 검색 트리는 가능한 이진 검색 트리 중 key를 찾는데에 걸리는 평균 시간이 가장 짧은 이진 검색 트리를 의미한다.
탐색시간은 원하는 키를 찾기까지 필요한 비교 횟수이다. 평균 탐색시간은 한 노드에 담긴 key m 이 찾고자하는 search key일 확률을 p m 라고 하고, key m 을 찾기까지의 비교횟수를 c m 이라고 할 때 p m 과 c m 의 곱의 합으로 나타내며 수식은 아래와 같다.
C m : key m 을 찾아가기 위한 비교횟수
P m : key m 이 search key일 확률
<이진 트리에서 사용하는 자료구조>
① 노드를 구조체로 나타냄
//노드를 구조체로써 나타냄 struct nodetype { keytype key nodetype* left nodetype* right } Typedef nodetype* node_pointer;
② A : 최적의 평균 탐색시간 값을 담은 배열
A[i][j] = key i 부터 key j 까지의 최적 평균 탐색시간
알고리즘 설계전략
① 재귀 관계식 정립
root를 추가할 때 마다 기존의 트리는 그 root의 subtree가 되므로 비교횟수가 각각 한번씩(c i (=1) x p i ) 더 늘어난다.
따라서 A[1][n] = A[1][k-1] + p 1 + … + p k-1 + p k + A[k+1][1] + p k+1 + … + p n
결론적으로 다음과 같은 재귀관계식이 도출된다.
② bottom-up 방식으로 해결
왼쪽 sub tree의 노드 개수가 0개일 때부터 n-1개일 때까지를 앞의 것의 결과를 토대로 순서대로 구한다. foundations of algorithms 교재 example 3.9에 이 과정에 대한 예시가 나와있다.
출처: foundations of algorithms, Richard Neapolitan, 도경구역
알고리즘 수도코드
최적의 평균 탐색 시간을 찾는 코드이다.
void optsearchtree(int n, const float p[], float& minavg, index R[][]) { index i, j, k, diagonal; float A[1..n+1][0..n]; for(i=1; i<=n; i++) { A[i][i-1] = 0; A[i][i] = p[i]; R[i][i-1] = 0; } A[n+1][n] = 0; R[n+1][n] = 0; for(diagonal = 1; diagonal <= n-1; diagonal++) for(i=1; i <= n-diagonal; i++) { j = i + diagonal; A[i][j] = minimum(A[i][k-1]+A[k+1][j])) + sum of pi ~ pj; //basic operation R[i][j] = a value of k that gave the minimum; } minavg = A[1][n]; } //배열 R을 이용해 트리 생성 nodepointer tree(index i, j) { index k; node_pointer p; k = R[i][j]; if(k==0) return NULL; else { p = new nodetype; p->key = key[k]; p->left = tree(i,k-1); p->right = tree(k+1,j); return p; } }
알고리즘 성능분석
basic operation : 각 k 값에 대한 덧셈, 비교연산 (A[i][j] = minimum(A[i][k-1]+A[k+1][j])) + sum of pi ~ pj;)
최적 이진 트리 탐색도 플로이드 알고리즘과 같이 every-case이다.
위 수도코드를 보면 j = i + diagonal이므로
– i에 대한 for문을 수행하는 횟수 = n – diagonal
– k에 대한 for문을 수행하는 횟수 = j-i+1 = (i+diagonal)-i+1 = diagonal+1
∴Θ(n3)
내가 그리는 세상 :: #5 최적 이진 탐색 트리(Optimal Binary Search Trees)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
//key1,key2…keyn typedef int index; // 트리에 들어갈 값들의 순번 const float p[ 6 ] = { NULL , 3. / 16 , 4. / 16 , 5. / 16 , 3. / 16 , 1. / 16 }; //각 값들의 확률 //정해진 구간의 모든 확률을 더하는 함수 float sum(index begin , index end ) { float sum_total = 0 ; for ( int i = begin ; i < = end ; i + + ) { sum_total + = p[i]; } return sum_total; } //optimal search tree를 구하는 함수 void optsearchtree(index n,index * * R) { index i, j, k, diagonal; float * * A = new float * [n + 2 ]; float min; for ( int s = 0 ; s < n + 2 ; s + + ) A[s] = new float [n + 1 ]; //계산않하는 구간 처리 for (i = 1 ; i < = n; i + + ) { A[i][i - 1 ] = 0 ; A[i][i] = p[i]; A[ 0 ][i - 1 ] = NULL ; R[i][i] = i; R[i][i - 1 ] = 0 ; R[ 0 ][i - 1 ] = NULL ; } A[ 0 ][n] = NULL ; A[n + 1 ][n] = 0 ; R[ 0 ][n] = NULL ; R[n + 1 ][n] = 0 ; //구간을 바꾸고. 구간 간격을 늘려가면서 평균 탐색 횟수가 최소인 구간 구하기 //diagonal 은 1~n-1. 행렬 A1~An까지 있으면 최대 간격은 n-1 for (diagonal = 1 ; diagonal < = n - 1 ; diagonal + + ) { for (i = 1 ; i < = n - diagonal; i + + ) { j = i + diagonal; min = A[i][i - 1 ] + A[i + 1 ][j] + sum(i,j); for (k = i; k < = j; k + + ) { if (min > = A[i][k – 1 ] + A[k + 1 ][j] + sum(i, j)) { min = A[i][k – 1 ] + A[k + 1 ][j] + sum(i, j); R[i][j] = k; } } A[i][j] = min; } } for (index i = 1 ; i < = n; i + + ) { for (index j = i; j < = n; j + + ) { printf ( "A[%d][%d]는::%f" , i, j, A[i][j]); printf ( " " ); } } for ( int s = 0 ; s < n + 2 ; s + + ) delete []A[s]; } int main() { int n = sizeof (p) / sizeof ( float ) - 1 ; //R[i][j]는 i~j에서의 최적 이진 탐색 트리의 루트 노드를 기록한 행렬이다 index * * R = new index * [n + 2 ]; for ( int i = 0 ; i < n + 2 ; i + + ) { R[i] = new index[n + 1 ]; //memset(R[i],0,sizeof(index)*(n+1)); } optsearchtree(n,R); for ( int i = 1 ; i < = n; i + + ) { for ( int j = i; j < = n; j + + ) { printf ( "R[%d][%d]는::%d" , i, j, R[i][j]); printf ( " " ); } } for ( int i = 0 ; i < n + 2 ; i + + ) delete [] R[i]; system( "pause" ); return 0 ; } Colored by Color Scripter
Optimal Binary Search Tree
트리들 중 어느 트리로 만들어야 좋을까?
key 를 search할 때 걸리는 시간을 적게 하고 싶다.
비교횟수를 최소화 하고 싶다.
각 key를 찾을 때까지 key comparison의 최솟값
각각의 key들을 search할 확률이 1/7 로 하지않고 비교한다.
여러개의 키로 이루어져 있다.
각 키를 search할 확률이 나와 있다.
1 >> key1 을 찾을 때까지 비교를 3번 하게 된다. 0.7 × 3 + 0.2 × 2 + 0,1 × 1
2 >> key2 을 찾을 때까지 비교를 3번 하게 된다. 0.7 × 2 + 0.2 × 3 + 0,1 × 1
3 >> key3 을 찾을 때까지 비교를 3번 하게 된다. 0.7 × 2 + 0.2 × 1 + 0,1 × 2
4 >> key4 을 찾을 때까지 비교를 3번 하게 된다. 0.7 × 1 + 0.2 × 3 + 0,1 × 2
5 >> key5 을 찾을 때까지 비교를 3번 하게 된다. 0.7 × 1 + 0.2 × 2 + 0,1 × 3
5 번째 방법으로 찾는 것이 Optimal Binary Search 이다.
Pi : i번째 k ey를 탐색 할 확률
Ci : i번째 key를 탐 색할 때 key 비교 의 횟수
Ci, Pi 곱의 합1을 최소화 시키는것이 목표이다.
Root에 Key i번째를 넣는다는 전제하에 생각해보자
Left sub tree 에는 Key i보다 작은 것들이 들어간다.
Right sub tree 에는 Key i보다 큰 것들이 들어간다.
Left sub tree 자체로서 ∑PiCi 가 Optimal Binary Search Tree가 되어야 한다.
Right sub tree 자체로서 ∑PiCi 가 Optimal Binary Search Tree가 되어야 한다.
Key 1번 부터 n번 까지의 평균 비교 횟수를 A[1][n] 이라고 하자.
A[1][n] = minimum( A[1][k-1] + A[k+1][n] )
이 식에서 key K를 seach 할때의 횟수가 빠져있다.
=> ∑PiCi 에서 Ci가 1이므로 >> Pi이다.
key 3을 찾는다면 하늘색 트리에서 3번 비교 + 빨간색 트리에서 4번 비교해야 한다.
확률값이 누적되므로 P1 + P2 +. .. + Pn 까지 더해줘야 하므로 결국엔 ∑Pk 이다.
A[1][n] = minimum( A[1][k-1] + A[k+1][n] ) + ∑ Pk
A[i][i-1] 은 empty tree이다.
k가 i가 되는 경우가 발생하므로 A[i][i-1] =0, A[j+1][j] = 0 으로 정의해 줘야 한다.
이게 끝이 아니라 P1 , P2, P3 를 더해줘야한다.
A[1]A[0] = 0
A[i][i] = p[i]
A[i]A[j] = minimum(i,j,k)
R[i][j] = k; // 최소가 되는 값을 R에 담아 놓는다.
diagonal 계산하기
최적 값 R에 저장
Optimal Binary Search Tree는 얘가 된다.
이진 탐색 트리의 특성
하나의 노드는 최대 두개까지의 자노드를 가질 수 있다.
부모 노드의 왼쪽 자식노드의 키 값은 부모 노드의 키 값보다 작다.
부모 노드의 오른쪽 자식 노드의 키 값은 부모 노드의 키 값보다 크다.
이진 탐색 트리의 예
이진 탐색 트리에서 어느 한 노드를 탐색하기 위한 최대 비교 횟수 : 그 트리의 깊이와 같음
이진 탐색 트리의 모든 노드가 각 한번씩 탐색된다고 가정할 때 총 비교 횟수
트리 (a) : 총 17번의 비교
트리 (b) : 총 19번의 비교
최적 이진 탐색트리 문제
: 트리의 각 노드가 탐색될 확률이 주어질 때, 그 트리의 평균 비교횟수가 최소인 탐색 트리를 구축하는 것이 목적이다.
이진 탐색트리를 구성하는 n개의 노드가 각각 K1, K2, … , Kn의 key 값을 갖는다고 가정
key 값 Ki가 탐색될 확률 : Pi
key 값 Ki를 찾는데 필요한 비교 횟수 : Ci
이때 이진 탐색트리의 평균 비교 횟수 = ∑CiPi
이 값을 최소화 하는 이진 탐색 트리를 구성하는 것이 목표이다.
예제 : 노드가 3개인 모든 가능한 이진 탐색트리
여기서 key 값과 확률을 다음과 같이 정한다.
K1 = 1, K2 = 2, K3 = 3
P1 = 0.5, P2 = 0.3, Pe = 0.2
그러므로 (c) 와 (e)로 구성된 이진트리가 탐색시간이 가장 짧다.
다음 그림이 최적 해를 보여준다고 가정
이진트리의 평균 탐색 시간을 구하는 수식
동적 프로그래밍 기법을 적용하기 위해서 순환 방정식으로 표현하면
이때 Ti,i-1 = 0 으로 정의 (1 <= i <= n+1) Ti,j 의 계산은 대각선 순서대로 한다. 예제 : 노드의 개수 n=4인 이진탐색트리의 각각의 키 값과 확률이 다음과 같다고 하자 위에서 정의된 순환방정식에 의해서 위의 결과를 테이블로 나타내면 다음과 같다. 또한 최솟값을 갖는 k값을 테이블로 나타낼 수 있다. 그러므로 최적 이진 탐색 트리는 아래와 같다.
최적 이진검색트리
이진검색트리
Binary Search Tree는 다들 한번쯤 봤을법한 검색트리기법중 하나이다. 이번 알고리즘은 이 이진검색트리에서 평균 검색비용을 최적화하는 알고리즘을 찾는 문제이다.
우선 이진검색트리의 조건에 대해 알아보자.
각 노드는 하나의 유일한 키를 가지고 있다.
모든 노드가 가진 키의 값은 그 노드의 왼쪽 서브트리의 값보다 크다
모든 노드가 가진 키의 값은 그 노드의 오른쪽 서브트리의 키의 값보다 작다.
정확한 정의
문제에 대한 정확한 정의를 알아보자
1. 키값이 k1부터 kn까지 주어진다.
2. 각 키의 검색 확률 pi가 주어진다.
3. 각 키의 비교 횟수 ci : ki를 검색하는데 필요한 키의 횟수
이러한 조건이 주어질 때 각 키의 평균 검색 비용은 : 검색확률 pi * 비교횟수 ci
그리고 전체 키의 평균값은 이 평균값의 summation이다.
Brute-Force
모든 경우의 수에 대해서 계산해 보고 최적의 이진트리를 선택한다.
이 경우 앞서 연쇄행렬곱셈에서도 사용했던 카탈란수를 다시 사용하게 될 것이다.
그렇다면, 그림을 통해서 입력사례를 알아보도록 하겠다.
키값 [10, 20, 30] / 확률 [0.7, 0.2, 0.1]이 주어진 이진트리의 경우 총 5가지의 경우의 수가 존재하는데
이 값들을 계산해보면 5번의 이진트리가 1.4의 값으로 가장 최적의 이진트리를 가지고 있다고 할 수 있다.
재귀관계식 만들기
• 1단계: 재귀 관계식을 찾는다.
𝑨: 이진검색트리를 만드는데 최적 검색비용의 행렬
𝑨[𝒊][𝒋]: 𝐾𝑖에서 𝐾𝑗까지 이진검색트리를 만드는데 최적 검색 비용
목표: 𝐾𝑖 ⋯ 𝐾𝑗를 (𝐾𝑖 ⋯ 𝐾𝑘−1)𝐾𝑘(𝐾𝑘+1 ⋯ 𝐾𝑗)로 분할하는 재귀 관계식 찾기
• 2단계: 상향식 방법으로 해답을 구한다.
초기화: 𝐴[𝑖][𝑖] = 𝑝𝑖
(주대각선을 𝑝𝑖 으로)
(주대각선을 𝑝𝑖 으로) 최종 목표:𝐴[1][𝑛].
상향식 계산: 대각선 1번, 대각선 2번, ⋯ , 대각선 𝑛 − 1번
CMM의 Diognal 해결법과 동일하다.
최종재귀관계식은 다음과 같다
즉 이진트리에서 Kk의 최적값은 좌측노드의 최적값 + 우측노드의 최적값 + k의까지의 모든 값의 최소값이다.
𝐴[1][𝑘 − 1]+𝐴[𝑘 + 1][𝑛]
코드 작성
def optsearchtree ( p ) : n = len ( p ) – 1 A = [ [ – 1 ] * ( n + 1 ) for _ in range ( n + 2 ) ] R = [ [ – 1 ] * ( n + 1 ) for _ in range ( n + 2 ) ] for i in range ( 1 , n + 1 ) : A [ i ] [ i – 1 ] = 0 A [ i ] [ i ] = p [ i ] R [ i ] [ i – 1 ] = 0 R [ i ] [ i ] = i A [ n + 1 ] [ n ] = 0 R [ n + 1 ] [ n ] = 0 for diagonal in range ( 1 , n ) : for i in range ( 1 , n – diagonal + 1 ) : j = i + diagonal A [ i ] [ j ] , R [ i ] [ j ] = minimum ( A , p , i , j ) return A , R def minimum ( A , p , i , j ) : minValue = INF minK = 0 for k in range ( i , j + 1 ) : value = A [ i ] [ k – 1 ] + A [ k + 1 ] [ j ] for m in range ( i , j + 1 ) : value += p [ m ] if ( minValue > value ) : minValue = value minK = k return minValue , minK
위와 같은 코드를 통해서 파이썬으로 해당 알고리즘을 구현 해 볼 수 있다.
최적 이진 검색 트리(BST: Binary Search Tree)
안녕하세요. 이번 포스팅에서는 동적 프로그래밍(Dynamic Programming)에서의 최적 이진 검색 트리(Optimal Binary Search Tree)에 대해서 알아보겠습니다.
1. 최적 이진 검색 트리 (Optimal Binary Search Tree)
최적 이진 검색트리를 보다 쉽게 이해하기 위해서 상황을 가정하며 설명드리겠습니다.
특정 문서에 중복이 허용된 여러개의 영어단어가 존재하는데 이를 한글로 번역해서 저장하는 프로그램을 필요로 한다고 가정합니다. 그렇다면 프로그램은 이를 수행하기 위해서 문서에 있는 각각의 영어단어에 접근하고, 이에 해당하는 한글 단어를 찾아야 합니다. n개의 영어 단어가 존재한다고 했을 때, 어떻게 해야 이를 효율적으로 수행하는 프로그램을 작성할 수 있을까요?
바로 이럴 때 사용될 수 있는 것이 이진 검색 트리입니다.
위의 상황을 생각하면 이때 이진 검색트리에서는 하나의 노드에 영어 단어에 해당하는 key와 그에 해당하는 한글데이터가 존재할 것 입니다. 문서에 있는 하나의 영어 단어 각각에 대해서 트리를 한번 검색해야 하므로 우리는 트리의 높이가 비슷하게 균형잡힌 이진 트리 검색을 이용한다면 단어 하나당 O(lg n)의 검색 시간을 보장할 수 있습니다.
그러나 이것이 과연 최적의 이진 트리일까요?
가정된 상황을 다시 살펴보면 영어 단어는 ‘중복’될 수 있다고 하였습니다. 즉, 특정 단어에 대해서는 빈번히 검색이 진행될 것이고 다른 단어에서는 검색이 거의 사용되지 않을 것 입니다.
이러한 상황에서 우리는 최적 이진 검색 트리(Optimal Binary Search Tree)를 사용할 수 있습니다.
최적 이진 검색 트리에서는, n개의 서로 다른 키 K =
이 오름차순으로 정렬된 상태로 주어지며 이러한 키를 바탕으로 이진 검색 트리가 구성됩니다. 그리고 각 키 ki에 대해 검색이 일어날 확률 pi또한 함께 존재합니다. 추가적으로, 우리는 어떤 단어 K에 대해서 탐색이 되지 않을 경우도 고려해야 합니다. 따라서 가상키라는 개념을 통해 이를 해결합니다. 가상키는 이진 검색 트리의 리프 노드로 배치될 것이며 특정 단어 K가 어떤 키 ki를 발견하지 못하면 가상키를 발견하게 될 것이고 이는 단어에 대한 해석을 찾지 못한 것으로 판단할 수 있습니다.
이러한 가상키는 n개의 노드를 가지는 이진 검색 트리의 리프노드들이므로 총 n+1개이며 d0는 k1보다 작은 모든 값을 나타내고 dn은 kn보다 큰 모든 값을 나타냅니다.
아래 사진을 보면 두개의 이진 검색 트리를 확인할 수 있습니다.
그림 아래에 존재하는 표는 각각의 항목이 일어날(검색될) 확률을 의미합니다.
Search Cost의 계산은 각 항목의 탐색시간(방문하는 노드수 = 깊이+1) * 확률의 총합이라고 하겠습니다.
먼저 첫번째 (a)의 이진 검색 트리를 보면 비슷하게 균형 잡힌 것을 볼 수 있습니다. 이러한 이진검색트리의 Search Cost는 그림에서 나온것과 같이 2.80입니다.
그리고 두번째, (b)의 이진 검색트리의 Search Cost는 2.75로써 (a)보다 작은 것을 볼 수 있습니다.
이렇게, 최적 이진 검색 트리는 단순히 높이를 균형있게 하는 것이 아니라 탐색시간을 최소로 하여 최적의 탐색시간을 갖도록 하는 것입니다.
일반적으로 최적 이진 검색 트리는 다음과 같이 정의됩니다.
위에서 언급한 바와 같이, 모든 탐색에서 방문하는 노드들의 회수의 최소를 갖도록 하는 것입니다.
2. 최적 이진 검색 트리의 최적 부분 구조
최적 이진 검색 트리의 최적 부분 구조를 찾기 위하여 부분 구조를 살펴보겠습니다.
어떤 이진 검색 트리의 서브 트리를 고려하면, 그 부분 구조는 1<= i <= j <= n에 대해 연속하는 범위 ki, ... , kj에 해당하는 키를 포함해야 합니다. 그리고 키 ki, ... , kj를 포함하는 서브트리는 그 해당 가상키 di-1, ... , dj도 포함해야 합니다. 이제 최적 이진 검색트리의 최적 부분 구조에 대해서 알아보겠습니다. 최적 이진 검색 트리 T가 있을 때, 키 ki, ... , kj를 포함하는 서브 트리 T'을 가진다면 이 서브 트리 T'은 키 ki, ... , kj와 가상 키 di-1, ... , dj를 가지는 부분 문제에 대해서도 최적이어야 합니다. 이러한 주장을 증명하기 위해서 cut&paste 방법을 적용합니다. T'보다 기댓값이 작은 서브 트리 T''이 존재한다고 가정합니다. 이때 T'을 잘라내고 그 자리에 T''을 붙여 넣으면 T보다 기댓값이 작은 이진 검색 트리가 나타나게 되고 이것은 T가 최적이라는 가정에 모순입니다. 그럼 이제 이러한 최적 부분 구조를 사용해서, 부분 문제에 대한 최적해를 구함으로써 주어진 문제에 대한 최적해를 구할 수 있음을 보여야 합니다. 위의 그림처럼 루트가 kr이고 키 ki, ... , kj를 갖는 최적 서브 트리가 있다고 합시다.(i <= r <= j) 그렇다면 아래 그림과 같이, 루트 kr의 왼쪽 서브 트리키는 ki, ... kr-1과 가상키 di-1, ... , dr-1를 포함할 것이며 오른쪽 서브 트리는 키 kr+1, ... , kj와 가상키 dr, ... , dj를 포함합니다. 이때 루트 kr에 대해 i부터 j까지의 모든 후보 루트 ki, ... , kj를 고려하면서 왼쪽 서브 트리로 ki, ... , kr-1를 포함하며 오른쪽 서브 트리로 kr, ... , kj를 포함하는 모든 최적 이진 검색트리를 검색하면 최적의 이진 검색 트리를 발견할 수 있습니다. 이때 만약 서브 트리의 루트를 ki로 선택한다면 왼쪽 서브 트리는 ki, ... ki-1을 포함합니다. 즉, 왼쪽 서브 트리는 어떤 키도 갖지 않는 빈 서브 트리가 됩니다. 그러나 왼쪽 서브 트리가 아무것도 갖지 않는 것은 아닙니다. 바로 가상키를 갖기 때문이죠. 왼쪽 서브 트리는 di-1, ... dr-1 의 가상키를 갖는다고 했으니, 루트가 ki인 서브 트리의 왼쪽 서브 트리는 di-1이라는 하나의 가상키만을 갖게 됩니다. 이것은 kj를 서브 트리의 루트로 잡았을때 오른쪽 서브트리에서 갖은 상황이 발생합니다. 3. 재귀해 이제 재귀적으로 최적해의 값을 찾을 준비가 되었습니다. i >= 1, j <= n, j >= i-1 인 키 ki, … , kj를 포함하는 최적 이진 검색 트리를 찾는 것으로 부분 문제의 범위를 정합니다.
위에서 언급한 바와 같이 j=i-1 일때는 실제키가 없고 가상키 di-1만 가지게 됩니다.
그리고 키 ki, … , kj를 포함하는 최적 이진 검색 트리를 찾는 기대비용을 e[i,j]로 정의하도록 하겠습니다.
결국 우리의 목표는 e[i,n]을 찾는 것입니다.
먼저, 우리는 j=i-1에 대해서 값을 쉽게 찾을 수 있습니다. 가상키 di-1만 존재하므로 기대 검색 비용, e[i,i-1] = qi-1 입니다.
이제 j >= i 일 때에 대해서 생각합니다. ki, … , kj 중에서 루트 kr을 선택해야 하며 왼쪽 서브 트리가 최적 이진 검색트리가 되어야 하며 오른쪽 서브 트리 또한 최적 이진 검색트리가 되어야 합니다.
이때 고려할 점이 있습니다. 만약 트리 T가 존재할 때 이 트리가 어떤 루트 N에 대해서 서브 트리가 된다면 T라는 트리의 검색비용에는 무슨 일이 벌어질까요? T 트리에 있는 모드의 깊이가 모드 1씩 증가하므로 T 트리의 검색 비용은 모든 노드들이 검색될 확률의 총합만큼 증가하게 됩니다.
그럼 점화식을 한번 알아보도록 하겠습니다.
먼저 위의 그림에서,
이것은, ki, … ,kj 의 키를 가진 서브 트리의 모든 확률의 합을 나타냅니다.
이를 통해 점화 식을 한번 세워보면, 위의 그림의 첫번째 식인,
e[i,j] = pr + (e[i,r-1] + w(i,r-1)) + (e[r+1,j] + w(r+1,j)) 이 나오게 됩니다.
식에서 의미하는 바를 그림으로 알아보겠습니다.
먼저 식에서 첫번째 인자인 pr은 위의 그림에 있는 트리의 루트가 검색될 확률을 의미합니다.
루트의 깊이는 0이므로 검색이 실행될때 pr*1만큼의 검색비용이 필요합니다.
그리고 e[i,r-1]은 왼쪽 서브트리, 그림에서 초록색을 가진 서브트리에 대한 검색비용을 의미합니다.
w(i,r-1)은 왼쪽 서브트리의 깊이가 1만큼 증가했으므로 그에 대해 왼쪽 서브트리의 모든 노드들의 확률의 합을 의미합니다. 그림에서는 빨간색 선으로 생각하시면 되겠습니다.
마찬가지로, e[r+1,j]는 그림에서 주황색테두리를 가진 서브트리를 의미하며, w(r+1,j)는 그림에서 파란색 선을 의미합니다.
위의 점화식을 보다 간단하게 하기 위해
w(i,j) = w(i,r-1) + pr + w(r+1,j)
라는 사실을 이용합니다.
그러면 위의 점화식은
e[i,j] = e[i,r-1] + e[r+1,j] + w(i,j)
가 됩니다.
그리고 r을 범위내 모든 값에 대해 탐색을 진행하고 그 중 최소의 검색 비용을 갖는 r을 찾아야 하므로 최종적인 점화식은 아래와 같습니다.
4. 알고리즘
먼저 Optimal BST를 구하기 위한 수도코드는 아래와 같습니다.
동적 프로그래밍을 이용하여 보다 효율적으로 탐색을 진행하기 위해 수도코드에서는 총 3개의 테이블을 사용합니다.
그리고 앞에서 이야기 했던 것처럼 e값을 재귀적으로 도출하면서 최종적인 목표에 도달하게 됩니다.
글의 서두에서 보여드렸던 키들을 이용하여 Optimal BST으로 계산하면 아래와 같은 테이블이 생성됩니다.
이러한 Optimal BST의 총 시간 복잡도는 O(n^3)입니다.
이렇게 하여 최적 이진 검색 트리(Optimal Binary Search Tree)에 대해서 알아보았습니다.
추가적인 궁금사항이나 내용에 대한 피드백은 댓글을 이용해주세요 🙂
반응형
키워드에 대한 정보 최적 이진 탐색 트리
다음은 Bing에서 최적 이진 탐색 트리 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.
이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!
사람들이 주제에 대해 자주 검색하는 키워드 최적이진탐색트리(OBST 설명), optimal binary search tree
- 정보컴퓨터
- 정컴
- 컴퓨터 교사
- 정컴 임용
- 정보컴퓨터 임용
- 최적이진탐색
- 최적이진탐색트리
- OBST
최적이진탐색트리(OBST #설명), #optimal #binary #search #tree
YouTube에서 최적 이진 탐색 트리 주제의 다른 동영상 보기
주제에 대한 기사를 시청해 주셔서 감사합니다 최적이진탐색트리(OBST 설명), optimal binary search tree | 최적 이진 탐색 트리, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.