트리에서 특정 데이터를 검색하고, 노드의 삽입/삭제 연산이 자주 발생하는 응용 문제에 가장 효과적인 이진 트리
왼쪽과 오른쪽이라는 방향성을 가지며 다루기가 매우 편리함
부모 노드를 중심으로[부모 보다 큰 데이터 노드]와 [부모 보다 작은 데이터 노드]로 구분됨
=왼쪽 서브 트리와 오른쪽 서브 트리의 중간 값은 이들의 부모 노
일반적으로 노드의 개수가 많아지면 트리의 높이가 커지게 됨
BS 트리가 2원(2-way) 탐색 트리임
✅ m원 탐색 트리
트리의 노드가 m개 이하의 가지를 가질 수 있는 탐색 트리 => 같은 수의 노드를 갖는 이진트리보다 낮은 높이의 m원 트리
m원: 탐색 트리가 가질 수 있는 자식 노드들의 개수
이진 탐색 트리의 확장된 형태
탐색 트리의 제한을 따르되 2개 이상(m개 이하)자식을 가질 수 있음
✅ m원 탐색 트리의 제한 조건
▪️ m원 탐색 트리 - 3원 탐색 트리
잎노드는 키값으로만 표기하고 내부노드 중 자식이 없는 포인터들은 표시하지 않음!
3원 탐색 트리는 최대 3개의 자식 노드를 가질 수 있음 == (정렬된) 키 값은 최대 2개
키 값들과 서브트리들의 값의 관계 확인 (어떤 것은 작고, 어떤 것은 크고, 어떤 것은 사잇값인지를 확인)
만약 키값이 60, 62이면 첫번째 자식 노드의 값은 60보다 작아야 하고, 두번째 자식 노드는 60과 62 사이의 값이어야 하고, 세번째 자식 노드는 62보다 큰 값이어야 함
🔸m원 탐색 트리 노드의 구조
🔸m원 탐색 트리의 탐색 연산
🔸m원 탐색 트리의 탐색
일반적으로 노드의 가지 개수가 많을수록(서브트리가 많을 수록), 최대 탐색 길이는 짧아짐(트리의 깊이가 얕으므로 더 빨리 찾을 수 있음)
예를 들어, 키가 255개인 경우 4원 트리로 구성하면 최대 경로 길이가 4가 됨
02. B 트리
✅ B 트리
m원 탐색 트리는 서브트리의 균형에 대해서는 특별히 제한하지 않았음
각 노드가 자식을 많이 갖게 하여 트리의 높이를 줄이고 전체적으로 균형을 유지한다면 탐색 성능을 더욱 향상할 수 있음
m원 탐색트리를 개선한 B트리는 인덱스 구조를 구현하는데 가장 일반적으로 사용함
차수 m인 B 트리의 탐색 경로 길이는 같은 개수의 키를 가지는 이상적인 m원 탐색 트리보다 길 수 있지만 키값을 삽입/삭제할 때 B트리를 유지하는 것이 더 쉬움
✅ B 트리의 조건
차수가 3인 B 트리
루트와 잎노드를 제외한 트리의 각 노드는 최소[ m/2 ]개의 서브트리를 갖는다
루트와 잎노드를 제외한 트리의 각 노드는 언제나 하나의 키값 혹은 두 개의 자식 노드를 가져야 함
트리의 루트는 최소한 2개의 서브트리를 갖는다
트리의 모든 잎노드는 같은 레벨에 있다
* [ ] 가우스 함수: 소수점을 포함하는 수를 그것보다 1큰 정수로 바꿈 예) [3/2] = [1.5] = 2
🔸B 트리에 키를 삽입하는 알고리즘
🔸B 트리의 노드 삽입
54 삽입(노드분리)
🔸B 트리에서 키를 삭제하는 알고리즘 - 잎노드에서 삭제
삭제할 키값을 포함한 노드를 찾는다
잎노드에서 삭제하는 경우
노드에서 키값을 삭제한다.
필요하면 재배열한다.
🔸B 트리에서 키를 삭제하는 알고리즘 - 내부노드에서 삭제
내부노드의 키값은 하위 노드에 대한 기준값(중간값)이기 때문에 삭제 시, 대체할 수 있는 적절한 값을 찾아야 한다. 보통 왼쪽 서브트리의 가장 큰 키값 또는 오른쪽 서브트리의 가장 작은 키값으로 대체할 수 있다. 이들은 모두 잎노드에 위치한다.
새로운 기준값(삭제된 자리에 올 키값)을 선택하여 해당 (잎)노드에서 삭제하고 그 값을 현재 키값을 삭제한 자리로 옮긴다. 즉 대체한 것이다.
기준값으로 대체하기 위해 키를 삭제한 잎노드가 정해진 개수의 키값을 갖지 않으면 트리를 재배열 한다.
▪️ 40 삭제(내부노드에서 삭제)
40을 삭제하면 중간값을 오른쪽 서브트리의 가장 앞에 있는 값을 올려줌
키값이 부족한 노드의 오른쪽 형제가 존재하고 키 개수가 여유있다면 오른쪽 키값의 가장 앞에 있는 것을 부모 노드로 한다는 규정
03. B*, B+ 트리
✅ B* 트리의 정의
노드의 약 2/3 이상이 채워지는 B 트리 → 높이가 더 줄어듬(B트리는 1/2)
노드가 꽉 차면 분리하지 않고, 키와 포인터를 재배치하여 다른 형제 노드로 옮김
삽입/삭제 시 발생하는 노드 분리를 줄이려고 고안됨
✅ B* 트리의 조건
차수가 m인 B* 트리는 다음 조건을 만족하는 B트리이다
① 공집합이거나 높이가 1 이상인 m원 탐색 트리이다 ② 루트 노드는 2개 이상 2 ⌊ (2m-2)/3 ⌋ + 1개 이하의 자식노드를 갖는다 ③ 내부노드는 최소한 ⌈ (2m-1)/3 ⌉개의 자식노드를 갖는다 ④ 모든 잎노드는 동일한 레벨에 놓인다 ⑤ 포인터가 k개인 잎이 아닌 노드는 k-1개의 키를 갖는다(루트노드 포함)
✅ B+ 트리의 정의
잎노드를 연결하는 포인터를 가짐. 왼쪽 잎노드가 가장 작은 값이고 오른쪽 잎노드가 가장 큰 값
탐색 트리로 구성하면 매우 빠르게 탐색할 수 있지만, 전체 데이터를 차례로 처리하기는 불편함
=> 데이터 전체를 이진 탐색 트리로 구성해놓으면 검색은 빠르지만! 전체 데이터를 다 찾아서 제일 큰 값부터 차례로 출력할 때는 굉장히 복잡
매번 왼쪽인지 오른쪽인지 비교해가면서 다음 노드를 찾아가면서 처리해야 함
스택을 써서 프로그래밍 하기 때문에 pop(), push() 연산이 추가되면 속도가 굉장히 느려짐
B+ 트리는 인덱스된 순차 파일을 구성하는데 사용됨
B 트리와 같이 각 노드의 키가 적어도 1/2이 채워져야 하는 점은 같음
잎노드를 순차적으로 연결하는 포인터 집합이 있다는 점에서 다름
잎노드의 마지막 포인터를 다음 키값을 갖는 노드를 가리킴
순차 처리를 할 때는 이 포인터를 이용해서(키값을 비교하지 않고) 차례로 다음 데이터에 접근해서 처리
모든 키값이 잎 노드에 있고 그 키값에 대응하는 실제 데이터(파일 내용)에 대한 주소를 잎노드만이 가지고 있음