算法-快速排序和归并排序
时间复杂度为\(O(nlogn)\)的排序有:快速排序、归并排序、堆排序。
1. 快速排序
- 时间复杂度:
- 平均时间复杂度为\(O(nlogn)\)
- 最坏情况时间复杂度为\(O(n^2)\)
- 空间复杂度:
- 平均空间复杂度为递归栈带来的\(O(logn)\)
- 最坏情况会退化为\(O(n^2)\)
- 稳定性:快速排序不是稳定排序算法。
public static void quickSort(int[] arr) {
if(arr == null || arr.length <= 1)
return ;
quickSort(arr, 0, arr.length-1);
}
private static void quickSort(int[] arr, int left, int right) {
if (left >= right)
return ;
int pivotIndex = partition(arr, left, right);
// 递归
// pivot 已经被放到了正确的位置,因此左右半区不需要包含pivotIndex了
quickSort(arr, left, pivotIndex-1);
quickSort(arr, pivotIndex+1, right);
}
private static int partition(int[] arr, int left, int right) {
// 选最左边的元素作为pivot
int pivot = arr[left];
int low = left+1;
int high = right;
//两个指针在中间某处相遇
while(low <= high) {
//low要找到第一个大于key的值
while(low <= right && arr[low] <= pivot) {
low++;
}
//high要找到第一个小于key的值
while(high > left && arr[high] >= pivot) {
high--;
}
if(low < high) {
swap(arr, low, high);
}
}
// 把pivot 放到两个指针相遇的位置
swap(arr, left, high);
return high;
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
2. 归并排序
\(T(n) = 2 * T(\frac{n}{2}) + O(n)\),其中合并两个有序数组的时间复杂度是\(O(n)\)。
- 时间复杂度:最好情况、最坏情况、平均情况都为\(O(nlogn)\)。
- 空间复杂度:\(O(n)\)。归并排序不是原地排序算法,需要额外的空间来存储tmp数组。
- 稳定性:归并排序是稳定排序算法,即相同的元素在排序后依然保持原来的顺序。
- 适用场景:链表、外存
public static void mergeSort(int[] arr){
if (arr == null || arr.length<=1)
return ;
int[] tmp = new int[arr.length];
mergeSort(arr, 0, arr.length-1, tmp);
}
private static void mergeSort(int[] arr, int left, int right, int[] tmp){
if(left >= right)
return;
int mid = left + (right - left) / 2; // 防止整数溢出
// 分支递归
mergeSort(arr, left, mid, tmp); // 左半部分
mergeSort(arr, mid+1, right, tmp); // 右半部分
// 合并两个有序数组
merge(arr, left, mid, right, tmp);
}
private static void merge(int[] arr, int left, int mid, int right, int[] tmp) {
int leftIndex = left;
int rightIndex = mid+1;
int tmpIndex = left; // 临时数组索引
while(leftIndex<=mid && rightIndex<=right) {
if(arr[leftIndex] <= arr[rightIndex]) {
tmp[tmpIndex++] = arr[leftIndex++];
} else {
tmp[tmpIndex++] = arr[rightIndex++];
}
}
// 将剩余元素拷贝到临时数组中
while(leftIndex <= mid) {
tmp[tmpIndex++] = arr[leftIndex++];
}
while(rightIndex <= right) {
tmp[tmpIndex++] = arr[rightIndex++];
}
// 将临时数组的内容拷贝回原数组
for(int i = left; i<=right; ++i) {
arr[i] = tmp[i];
}
}

浙公网安备 33010602011771号