版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Apple_hzc/article/details/83471830
一、堆排序
构建堆
无序数组建立堆最直接的方法是从左到右遍历数组进行上浮操作。一个更高效的方法是从右至左进行下沉操作,如果一个节点的两个节点都已经是堆有序,那么进行下沉操作可以使得这个节点为根节点的堆有序。叶子节点不需要进行下沉操作,可以忽略叶子节点的元素,因此只需要遍历一半的元素即可。
交换堆顶元素与最后一个元素
交换之后需要进行下沉操作维持堆的有序状态。
class Solution{
public static void heapSort(int[] nums) {
if (nums == null || nums.length == 0) {
return ;
}
int n = nums.length;
for (int i = n / 2 - 1; i >= 0; i--) {
adjustHeap(nums, i, n);
}
for (int i = n - 1; i >= 0; i--) {
int temp = nums[i];
nums[i] = nums[0];
nums[0] = temp;
adjustHeap(nums, 0, i);
}
}
public static void adjustHeap(int[] nums, int current, int n) {
int temp = nums[current], left = 2 * current + 1;
while (left < n) {
if (left + 1 < n && nums[left] < nums[left + 1]) {
left++;
}
if (temp < nums[left]) {
nums[current] = nums[left];
current = left;
} else {
break;
}
left = 2 * left + 1;
}
nums[current] = temp;
}
}
性能分析
一个堆的高度为 logN,因此在堆中插入元素和删除最大元素的复杂度都为 logN。对于堆排序,由于要对 N 个节点进行下沉操作,因此复杂度为 NlogN。堆排序是一种原地排序,没有利用额外的空间。
二、快速排序
基本原理
- 归并排序将数组分为两个子数组分别排序,并将有序的子数组归并使得整个数组排序。
- 快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。
切分
取 a[l] 作为切分元素,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于等于它的元素,交换这两个元素。不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[l] 和 a[j] 交换位置。
class Solution{
public static void quickSort(int[] nums, int left, int right) {
if (nums == null || nums.length == 0 || left >= right) {
return ;
}
int basePostion = partition(nums, left, right);
quickSort(nums, left, basePostion - 1);
quickSort(nums, basePostion + 1, right);
}
public static int partition(int[] nums, int left, int right) {
int i = left, j = right, base = nums[left];
while (i < j) {
while (i < j && base <= nums[j]) {
j--;
}
if (i < j) {
nums[i++] = nums[j];
}
while (i < j && base >= nums[i]) {
i++;
}
if (i < j) {
nums[j--] = nums[i];
}
}
nums[i] = base;
return j;
}
}
性能分析
快速排序是原地排序,不需要辅助数组,但是递归调用需要辅助栈。
快速排序最好的情况下是每次都正好能将数组对半分,这样递归调用次数才是最少的。这种情况下比较次数为 CN=2CN/2+N,复杂度为 O(NlogN)。
最坏的情况下,第一次从最小的元素切分,第二次从第二小的元素切分,如此这般。因此最坏的情况下需要比较 N2/2。为了防止数组最开始就是有序的,在进行快速排序时需要随机打乱数组。