快速排序(Quicksort)是一种高效的排序算法,采用了分治法(Divide and Conquer)策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。
快速排序的基本步骤
- 选择基准:从数列中挑出一个元素,称为“基准”(pivot)。
- 分区过程:重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割结束之后,该基准就处于数列的中间位置。这个称为分割(partition)操作。
- 递归排序子序列:递归地将小于基准值的子序列和大于基准值的子序列进行快速排序。
快速排序的伪代码
plaintext
function quicksort(array)
if length(array) ≤ 1
return array
pivotIndex ← choosePivot(array)
pivot ← array[pivotIndex]
swap pivot with the last element of the array
storeIndex ← first element of the array
for i from first to second last element
if array[i] < pivot
swap element at i with element at storeIndex
increment storeIndex
swap pivot with the element at storeIndex
leftSubArray ← subarray of elements before storeIndex
rightSubArray ← subarray of elements after storeIndex
return concatenate(quicksort(leftSubArray), pivot, quicksort(rightSubArray))
快速排序的 JavaScript 实现
以下是一个简单的快速排序的 JavaScript 实现:
javascript
function quickSort(arr, left = 0, right = arr.length - 1) {
if (left < right) {
const partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
return arr;
}
function partition(arr, left, right) {
const pivot = arr[right]; // 选择最后一个元素作为基准
let i = left - 1; // i 用来标记小于基准的元素的最后一个位置
for (let j = left; j < right; j++) {
if (arr[j] < pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]]; // 交换元素
}
}
[arr[i + 1], arr[right]] = [arr[right], arr[i + 1]]; // 把基准元素放到中间位置
return i + 1; // 返回基准元素的位置
}
// 测试
const unsortedArray = [3, 6, 8, 10, 1, 2, 1];
console.log("Unsorted:", unsortedArray);
const sortedArray = quickSort(unsortedArray);
console.log("Sorted:", sortedArray);
时间复杂度
- 最好情况:O(n log n),当每次都能均匀分割数组时。
- 平均情况:O(n log n),这是快速排序最常见的情况。
- 最坏情况:O(n^2),当输入数组已经是有序的或者是逆序的,并且每次都选择第一个或最后一个元素作为基准时。
空间复杂度
快速排序的空间复杂度为 O(log n),这是由于递归调用栈的深度决定的。
选择基准的策略
选择基准的策略会影响到快速排序的效率。常见的选择方法有:
- 选择第一个元素;
- 选择最后一个元素;
- 随机选择;
- 选择中位数。
随机选择基准可以减少最坏情况的发生概率,而选择中位数作为基准可以尽量保证每次划分的平衡性,从而接近最优情况的时间复杂度。
快速排序因其高效和简洁成为了许多场景下首选的排序算法。