Ответ
Быстрая сортировка (QuickSort) имеет среднюю сложность O(n log n). В худшем случае (например, при неудачном выборе опорного элемента) сложность может деградировать до O(n²). Однако на практике QuickSort часто быстрее других алгоритмов сортировки из-за эффективного использования кэша и малых констант.
fun quickSort(arr: IntArray, low: Int = 0, high: Int = arr.size - 1) {
if (low < high) {
val pivotIndex = partition(arr, low, high)
quickSort(arr, low, pivotIndex - 1)
quickSort(arr, pivotIndex + 1, high)
}
}
fun partition(arr: IntArray, low: Int, high: Int): Int {
val pivot = arr[high]
var i = low
for (j in low until high) {
if (arr[j] < pivot) {
arr.swap(i, j)
i++
}
}
arr.swap(i, high)
return i
} Ответ 18+ 🔞
Э, слушай, вот про быструю сортировку расскажу, а то народ часто путается, ёпта. В среднем-то она летает как угорелая — O(n log n), это вообще красота. Но есть тут одна хитрая жопа, чувак.
Представь, что опорный элемент выбираешь как последний в массиве, а массив тебе уже отсортированный подсунули. Ну или почти отсортированный. И что получается? Разделение каждый раз получается пиздец какое кривое — один элемент в одной части, а всё остальное в другой. И пошло-поехало рекурсивно вызываться, и в итоге получается не O(n log n), а полный пиздец — O(n²). Ядрёна вошь! То есть из быстрой она превращается в медленную, как черепаха в болоте.
Но не спеши охуевать! На практике-то она всё равно часто всех рвёт. Почему? Да потому что константы у неё маленькие, да и кэш процессора она использует так, что другим сортировкам и не снилось. В большинстве библиотек её и используют, только там умные ребята опорный элемент выбирают не абы как — берут медиану из трёх, например, или вообще рандомно. Это чтобы тот самый худший случай на практике встретить было как выиграть в лотерею — возможно, но овердохуища маловероятно.
Вот, глянь на код, тут всё просто, если вдуматься.
fun quickSort(arr: IntArray, low: Int = 0, high: Int = arr.size - 1) {
if (low < high) {
val pivotIndex = partition(arr, low, high)
quickSort(arr, low, pivotIndex - 1)
quickSort(arr, pivotIndex + 1, high)
}
}
fun partition(arr: IntArray, low: Int, high: Int): Int {
val pivot = arr[high]
var i = low
for (j in low until high) {
if (arr[j] < pivot) {
arr.swap(i, j)
i++
}
}
arr.swap(i, high)
return i
}
Видишь? Берём последний элемент за опору (pivot). Потом бегаем по массиву, всё, что меньше опоры, пихаем влево. В конце эту самую опору ставим на правильное место — между теми, кто меньше, и теми, кто больше или равен. И вуаля! Массив разделён. А дальше просто повторяем эту хуйню для левой и правой части, пока всё не отсортируется. Элементарно, Ватсон!
Так что да, в теории есть подлянка, но на практике — это один из главных кадров в мире сортировок. Просто не будь распиздяем и выбирай опору с умом, а не как бог на душу положит.