Sorting
Merge Sort (Top-Down)
Split the array recursively, sort each half, then merge two sorted runs into one sorted result.
Algorithm
Basic Implementation
basic.sh
#!/usr/bin/env bash
set -euo pipefail
merge_sort() {
local values=("$@")
local n=${#values[@]}
if ((n <= 1)); then
printf '%s\n' "${values[@]}"
return
fi
local mid=$((n / 2))
local left=("${values[@]:0:mid}")
local right=("${values[@]:mid}")
local sorted_left=()
local sorted_right=()
mapfile -t sorted_left < <(merge_sort "${left[@]}")
mapfile -t sorted_right < <(merge_sort "${right[@]}")
local i=0
local j=0
while ((i < ${#sorted_left[@]} && j < ${#sorted_right[@]})); do
if ((sorted_left[i] <= sorted_right[j])); then
printf '%s\n' "${sorted_left[i]}"
i=$((i + 1))
else
printf '%s\n' "${sorted_right[j]}"
j=$((j + 1))
fi
done
while ((i < ${#sorted_left[@]})); do
printf '%s\n' "${sorted_left[i]}"
i=$((i + 1))
done
while ((j < ${#sorted_right[@]})); do
printf '%s\n' "${sorted_right[j]}"
j=$((j + 1))
done
}
arr=(5 1 4 2 8)
mapfile -t arr < <(merge_sort "${arr[@]}")
printf '['
sep=''
for v in "${arr[@]}"; do
printf '%s%d' "$sep" "$v"
sep=', '
done
printf ']\n'
Complexity
- Time: O(n log n)
- Space: O(n)
- Stable: yes
Implementation notes
arr=(5 1 4 2 8)is the pinned Bash indexed array. The script now sorts it withmerge_sort, not externalsort.merge_sort()copies its arguments into a local array withlocal values=("$@"), then usesn=${#values[@]}as the base-case size.- For more than one value,
mid=$((n / 2))splits local arrays with Bash slice syntax:left=("${values[@]:0:mid}")andright=("${values[@]:mid}"). - Bash functions cannot return arrays directly. Each recursive call prints one
sorted value per line, and
mapfile -t sorted_left < <(merge_sort ...)captures that stdout stream back into a local array. - That stream shape is intentionally simple for these pinned integers: one number per line, no spaces inside values.
- The merge loop compares numbers with Bash arithmetic evaluation:
((sorted_left[i] <= sorted_right[j])). - The
<=branch chooses the left value first on ties, so equal values keep their left-before-right order. - Remaining left or right values are printed by the two cleanup
whileloops.
Replay steps
start: [5, 1, 4, 2, 8]
split: left [5, 1], right [4, 2, 8]
sort: left [1, 5], right [2, 4, 8]
merge: [1, 2, 4, 5, 8]
- Final output uses the same formatter as nearby Bash sorting lessons:
printf '[',sep='',for v in "${arr[@]}",printf '%s%d' "$sep" "$v", thenprintf ']\n'.
divide and conquer
Each recursive call solves a smaller sorted subproblem.
merge step
Two sorted halves are combined by repeatedly taking the smaller front item.