Сортировка слиянием (Merge Sort)
Сортировка слиянием (Merge Sort) — это эффективный, стабильный алгоритм сортировки, использующий подход "разделяй и властвуй". Он работает следующим образом:
fun mergeSort(nums: IntArray, left: Int = 0, right: Int = nums.size - 1) {
if (left < right) {
val mid = left + (right - left) / 2
// Рекурсивная сортировка левой и правой половин
mergeSort(nums, left, mid)
mergeSort(nums, mid + 1, right)
// Слияние отсортированных половин
merge(nums, left, mid, right)
}
}
private fun merge(nums: IntArray, left: Int, mid: Int, right: Int) {
val leftArray = nums.sliceArray(left..mid)
val rightArray = nums.sliceArray(mid + 1..right)
var i = 0 // Индекс для левой части
var j = 0 // Индекс для правой части
var k = left // Индекс для результирующего массива
// Слияние двух временных массивов обратно в nums[left..right]
while (i < leftArray.size && j < rightArray.size) {
if (leftArray[i] <= rightArray[j]) {
nums[k] = leftArray[i]
i++
} else {
nums[k] = rightArray[j]
j++
}
k++
}
// Копируем оставшиеся элементы левой части, если есть
while (i < leftArray.size) {
nums[k] = leftArray[i]
i++
k++
}
// Копируем оставшиеся элементы правой части, если есть
while (j < rightArray.size) {
nums[k] = rightArray[j]
j++
k++
}
}
// Пример использования:
val nums = intArrayOf(4, 2, 7, 1, 9)
mergeSort(nums)
println(nums.joinToString(", ")) // Вывод: 1, 2, 4, 7, 9
mergeSort
массив делится на две части с помощью вычисления среднего индекса mid
.mergeSort
применяются к левому подмассиву nums[left..mid]
и правому подмассиву nums[mid+1..right]
.merge
объединяет два отсортированных подмассива в один.leftArray
и rightArray
, содержащие элементы левой и правой частей исходного массива.i
, j
, и k
используются для отслеживания текущих индексов в левой части, правой части и объединенном массиве соответственно.leftArray
или rightArray
, они копируются в исходный массив.Преимущества:
O(n log n)
в худшем, среднем и лучшем случаях.Недостатки:
O(n)
для временных массивов.fun mergeSortIterative(nums: IntArray) {
val n = nums.size
var currSize: Int
var leftStart: Int
// Сортируем подмассивы разного размера от 1 до n/2
currSize = 1
while (currSize <= n - 1) {
leftStart = 0
while (leftStart < n - 1) {
val mid = minOf(leftStart + currSize - 1, n - 1)
val rightEnd = minOf(leftStart + 2 * currSize - 1, n - 1)
merge(nums, leftStart, mid, rightEnd)
leftStart += 2 * currSize
}
currSize *= 2
}
}