六、快速排序
通过一次排序将数组分为两部分,左边部分是比基准元素小的部分,右边部分是比基准元素大的部分,即准确找到了基准元素应该在的位置。与归并排序不同,归并排序用一个临时数组存储当前两个待排序部分排序后的顺序。快速排序是直接在原数组上找到基准元素应该在的位置。
1、算法描述
在数组中选择一个元素作为基准元素,通常选择当前待排序序列中第一个元素。
用一个临时变量保存基准元素的值
设置两个指针low和high,从两端开始遍历,先从high开始,遇到比基准元素小的就放到low位置
此时low位置的元素是基准元素,交换之后,low当前位置就是比基准元素小的数
然后从low位置开始寻找第一个比基准元素大的元素。
直到low == high,一次递归结束
2、代码
public static void quickSort(int[] nums,int low,int high){
if(low < high){
int index = getIndex(nums,low,high);
quickSort(nums,low,index - 1);
quickSort(nums,index+1,high);
}
}
private static int getIndex(int[] nums, int low, int high) {
int temp = nums[low];
while(low < high){
while(nums[high] >= temp && high > low){
high--;
}
//当nums[high] 小于temp时
nums[low] = nums[high];
while(low < high && nums[low] <= temp){
low++;
}
nums[high] = nums[low];
}
nums[low] = temp;
return low;
}
七、堆排序
堆是具有以下性质的完全二叉树:
1)每个结点的值都大于或等于左右孩子的值,称为大根堆
2)每个结点的值都小于或等于左右孩子的值,称为小根堆
根据数组的下标进行编号,则有
大根堆:nums[i] >= nums[2*i + 1] && nums[i] >= nums[2*i + 2]
小根堆:nums[i] <= nums[2*i + 1] && nums[i] <= nums[2*i + 2]
1、算法描述
1)建堆
在当前结点i下,先拿到左右孩子的下标
在保证左右孩子下标不越界的情况下,依次比较三个值的大小,得到最大的元素的下标,用一个max指针保存。
如果max和i不同,则交换两元素,并且递归max结点建堆
2)排序
依次将堆顶元素和最后一个元素交换,再从堆顶元素开始建堆
交换之后,最后一个元素就是最大的元素,剩余数组继续排序建堆
2、代码
public class HeapSort {
public static void sort(int[] arr){
//建堆
for(int i = arr.length / 2 - 1; i >= 0; i--){
heapify(arr,i,arr.length);
}
//排序
for(int i = arr.length - 1; i >= 0; i--){
//把堆顶元素和最后一个元素进行交换
swap(arr,0,i);
//交换之后,从堆顶开始维护堆
heapify(arr,0,i);
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* @param arr 数组
* @param i 当前需要调整的结点下标
* @param length 数组的长度
*/
private static void heapify(int[] arr, int i, int length) {
int max = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
//保证left和right不越界
if(left < length && arr[max] < arr[left]){
max = left;
}
if(right < length && arr[max] < arr[right]){
max = right;
}
if(max != i){
swap(arr,i,max);
heapify(arr,max,length);
}
}
}