카테고리 없음

[DataBase] Btree

개바리여리 2025. 6. 14. 15:42

 

 

이진 탐색 트리 (BST)

 

모든 노드의 왼쪽 서브트리는 해당 노드의 값보다 작은 값들로만 이루어지고,

모든 노드의 오른쪽 서브트리는 해당 노드의 큰 값들만 가지게 된다.

또한 자녀 노드를 최대 2개까지만 가질 수 있다.

 

근데 자녀 노드를 N개 만큼 느려 더욱 많은 데이터를 저장하고 효율적인 검색을 위해 B-Tree 구조가 탄생하게 된다.

여러 자녀 노드를 가지면서 노드 하나에 여러 키값들을 저장할 수 있게 된다.

 

  • 노드 수가 작아 → 트리 높이도 작고 → 디스크 I/O 적음
  • 디스크에서 읽고 쓰는 것을 최소화하기 위해 고안됨

 

 

 

B트리

 

 

왼쪽 서브트리는 10보다 작은 값을 가지고

가운데 서브트리는 10~20사이에 값을 가지게 되고

오른쪽 서브트리는 20보다 큰 값을 가지게 된다.

 

B 트리는 최대 몇개의 자녀노드를 가지느냐에 따라 성질이 조금 달라진다.

 

B tree 파라미터

 

M : 각 노드의 최대 자녀수  --> 최대 M개의 자녀를 가질 수 있는 트리는 M차 B 트리라고 한다.

M - 1: 각 노드의 최대 Key 수

M / 2 : 각 노드의 최소 자녀 노드의 수

 3차 B tree 라고 한다면 3/2 = 1.5 이기에 올림해서 2가 된다.

(단 root node와 자녀가 없는 leaf node 는 제외)

M/2 -1 : 각 노드의 최소 Key 수  (root node는 제외)

 

노드가 최소 하나의 key를 가지기 때문에 몇 차인지에 따라 상관없이 internal 노드는 최소 두 개의 자녀노드를 가진다.

 

 

B Tree의 데이터 추가

 

추가는 항상 맨 하단에 있는 leaf 노드에서 이루어지며 노드가 초과되면 가운데 key를 기준으로 

좌우 key 들을 분할하고 가운데 key는 승진한다.

 

1 [탐색] 삽입할 위치(리프 노드)를 찾는다.

 
             [30]
            /    \
        [10, 20]  [40, 50]
 
 

새로운 값 15를 삽입하고자 할 때:

  • 15 < 30 → 왼쪽 자식 [10, 20] 탐색
  • 해당 노드에 삽입 시도

2 [삽입] 리프 노드에 공간이 있다면, 정렬된 위치에 삽입

  • [10, 20] → 아직 2개 → 최대치 안 넘음
  • 삽입 후 정렬 → [10, 15, 20]
 
             [30]
            /    \
    [10, 15, 20]  [40, 50]

3 [Split] 만약 리프 노드가 가득 찼다면, 분할(Split)

예: [10, 15, 20] 이 꽉 찼는데 12를 삽입하고 싶다

  1. 12를 삽입 → [10, 12, 15, 20] (정렬된 상태로 삽입)
  2. 노드가 초과함 → 중간 키를 기준으로 Split
    • 중간 키: 12
    • 왼쪽 노드: [10]
    • 오른쪽 노드: [15, 20]
    • 중간 키 12를 부모 노드로 올림
           [12, 30]
          /    |     \
    [10]   [15,20]  [40,50]

4 [부모도 꽉 찼을 경우] → 부모도 Split 발생 → 재귀적으로 위로 전파

  • 부모 노드도 꽉 차있을 경우 → 부모도 분할
  • 이 과정이 루트까지 가면 → 루트가 분할되고 트리 높이 증가
 
  루트 분할 전:
       [20, 40]
      /   |    \
   [10] [30] [50]

  새로운 값 `35` 삽입 → 분할 필요

 

 

* B Tree는 모든 leaf 노드들이 같은 레벨에 있는 밸런스 트리이다. --> 시간복잡도가 Olog N 이 된다.

 

 

 

B Tree의 데이터 삭제

삭제도 항상 leaf 노드에서 발생한다. 

삭제후 최소 key 수 보다 적어졌다면 재조정에 들어간다.

 

3차 B tree에서 각 노드의 최소 Key 수 = 3/2 -> 2(올림) - 1 = 1 

 

출처 : 유튜브 쉬운코딩 https://www.youtube.com/watch?v=H_u28u0usjA&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=30

 

여기서 5를 삭제하게 된다면 최소 key가 만족할 수 없기때문에 

1. Key 수가 여유있는 형제의 지원(1,2 와 8,9)을 받는다.

2. 지원이 불가능하면 부모의 지원을 받고 형제와 합친다.

3. 2번후 부모도 만족하지 못한다면 다시 재조정에 들어간다.

 

위에서는 2를 지원받고 2를 승격하고 그 다음값인 3을 밑으로 내린다.

 

 

여기서 3을 삭제하게 되면 조건이 만족되지 않기 때문에 여유가 있는 오른쪽에 지원을 받는다.

8은 승격하고 7은 내려오게 된다.

 

 

또 다시 7를 삭제한다고 할때는 형제는 모두 지원이 불가능 하기에 부모에게 2를 받고 삭제된 노드는 형제노드에 흡수된다.

 

 

 

internal 노드에서 데이터 삭제

- internal 노드에 있는 데이터를 삭제하려면 leaf 노드에 있는 데이터와 위치를 바꾼후 삭제한다.

(삭제할 데이터의 선임자나 후임자와 위치를 바꿔주어야 한다.)

 

선임자(해당 노드의 값 보다 작은 데이터들 중 가장 큰데이터)를 기준으로 15를 삭제하는 경우는 아래와 같다.

 

 

9와 위치를 바꾸어 삭제하면 된다.

 

 

 

 

 

해당 글은 유튜버 '쉬운코드' 님의 영상의 내용을 적었습니다.

출처 : https://www.youtube.com/watch?v=H_u28u0usjA&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=30