Yasir Explains/Algorithms/M-way Trees, B-Trees & Amortized Analysis/B-Tree Deletion: Borrowing & Merging
M-way Trees, B-Trees & Amortized Analysis

B-Tree Deletion: Borrowing & Merging

On this page

The Problem: UnderflowBorrowing vs. Merging — the two repairsExample: Deletions from the t = 3 TreeStep 1 — Delete 30 (Merge case)Step 2 — Delete 60 (Predecessor swap → leaf delete, no underflow)Step 3 — Delete 90 (Merge case)A Clean Borrowing ExampleComplexity
M-way Trees, B-Trees & Amortized Analysis

B-Tree Deletion: Borrowing & Merging

Removing a key can leave a node too empty. Learn the three repair cases — leaf delete, borrow from a sibling, and merge with a sibling.

The Problem: Underflow

Deletion is the mirror of insertion. Removing a key can push a node below its minimum of t − 1 keys — a state called underflow. Every deletion case exists to either avoid or repair underflow while keeping all B-tree invariants true (balanced, sorted, correct child counts).

There are three basic situations, listed here from cheapest to most expensive:

CaseWhen it appliesAction
1. Leaf delete, no underflowKey is in a leaf that has more than t − 1 keysJust remove it
2. Borrow from a siblingThe node would underflow, but an adjacent sibling has > t − 1 keys to spareRotate a key through the parent
3. Merge with a siblingThe node would underflow and both siblings are at the minimumFuse two nodes + a parent key into one

Deleting a key from an internal node adds one wrinkle: we can't just remove a separator (its children depend on it), so we first replace it with its inorder predecessor or successor (which lives in a leaf) and then delete that key from the leaf — reducing every case to a leaf deletion.

Borrowing vs. Merging — the two repairs

Borrowing (rotation) — used when a neighbour is rich enough to lend:

Example
Underflow in right child; left sibling has a spare key (t = 3, min 2 keys).
[ ... 50 ... ] [ ... 40 ... ]
/ \ borrow / \
[10|20|30|40] [70] ───────────► [10|20|30] [50|70]
(4 keys) (underflow) (3 keys) (2 keys, fixed)

The parent separator 50 drops down into the starved node, and the sibling's largest key 40 rises to take 50's place. One key shifts through the parent — the parent's key count is unchanged, so nothing propagates upward. Borrowing is always a local, O(1)-node fix.

Merging — used when no neighbour can spare a key (both siblings sit at t − 1):

Example
Underflow; both siblings minimal (t = 3, min 2). Fuse child + separator + sibling.
[ 50 | 90 ] [ 90 ]
/ | \ merge / \
[..] [70|80] [100|110] ─────────► [..] [70|80|50→ ... ]
↑ underflow (2t−1 keys)

The separator from the parent is pulled down and combined with the two minimal nodes into a single node of 2t − 1 keys. Because the parent loses a key, a merge can cause the parent to underflow too — so merging may cascade upward, and if the root ends up empty, the tree shrinks in height by one. Merging is the exact inverse of a split.

Example: Deletions from the t = 3 Tree

We continue with the B-tree built in the previous topic — minimum degree t = 3 (min 2 keys, max 5 keys per non-root node), holding 10 … 150:

We now delete 30, 60, 90 one at a time. All three live in the root, so each is an internal-node deletion that first looks to its two surrounding children.

Step 1 — Delete 30 (Merge case)

30 separates children [10|20] and [40|50]. Both have exactly t − 1 = 2 keys, so neither can lend a predecessor or successor. This forces a merge: pull 30 down and fuse the two children into one node, then remove 30 from the fused leaf.

Example
merge [10|20] + 30 + [40|50] → [10|20|30|40|50], then delete 30
→ [10|20|40|50]

The root loses key 30 and one child pointer:

➡️ Case used: deletion using merging with a sibling.

Step 2 — Delete 60 (Predecessor swap → leaf delete, no underflow)

60 now separates [10|20|40|50] and [70|80]. The left child has 4 keys, comfortably above the minimum — so we replace 60 with its inorder predecessor (the largest key to its left, 50), then delete 50 from that leaf. The leaf drops from 4 keys to 3, still ≥ 2, so no underflow occurs.

Example
replace 60 with predecessor 50 → root: [50 | 90 | 120]
delete 50 from leaf [10|20|40|50] → [10|20|40] (3 keys, no underflow)

➡️ Case used: deletion from a leaf node without underflow (after swapping the internal key with its predecessor).

Step 3 — Delete 90 (Merge case)

90 separates [70|80] and [100|110] — both minimal (2 keys), so again neither can lend. We merge: pull 90 down, fuse the two leaves, then remove 90.

Example
merge [70|80] + 90 + [100|110] → [70|80|90|100|110], then delete 90
→ [70|80|100|110]

The root drops to just two keys — still valid, since the root's minimum is 1:

➡️ Case used: deletion using merging with a sibling.

Summary of the three deletions: 30 → merge, 60 → leaf delete without underflow (via predecessor swap), 90 → merge.

A Clean Borrowing Example

The sequence above happened to trigger only merge and no-underflow cases. Here is a compact example that isolates borrowing, again with t = 3 (min 2 keys):

Example
Start: [50]
/ \
[10|20|30|40] [60|70]
Delete 60 → leaf [60|70] becomes [70] → only 1 key < min 2 → UNDERFLOW
Left sibling [10|20|30|40] has 4 keys → it can lend → BORROW:
• parent separator 50 drops into the starved leaf → [50|70]
• sibling's largest key 40 rises to become the separator
Result: [40]
/ \
[10|20|30] [50|70] ← both nodes valid, height unchanged

Borrowing kept the fix local — no key count changed in the parent, so nothing propagated upward. Had the left sibling held only 2 keys, we would have been forced to merge instead.

➡️ Case used: deletion using borrowing from a sibling.

Complexity

Deletion walks a single root-to-leaf path. At each level it does O(1) sibling checks and O(t) key shifting. A borrow stops immediately; a merge may cascade up the path but at most once per level.

  • Comparisons / CPU work: O(t · log_t n).
  • Disk accesses: O(log_t n).

As with insertion, expensive restructuring (merges cascading, height shrinking) is rare — most deletions are a simple leaf removal — which is why the amortized cost of B-tree updates stays low.

Complexity Analysis

Time Complexity

O(t · log_t n)

Space Complexity

O(log_t n)

Single downward pass; O(log_t n) disk accesses. Merges may shrink height by 1.

Growth Rate Comparison

n (input size)O(1)O(log n)O(n)O(n log n)O(n²)