归并排序
算法原理(从小到大为例):
- 将数组分成两部分,每部分分别排序,形成有序的两部分,然后遍历比较每部分的头部元素,形成新的数组
- 其中,每部分分别排序,递归使用步骤1,递归终止情况为:需要排序的部分只有一个元素
图片来源:极客时间,《数据结构与算法之美》,12章
时间复杂度:O(n*log(n)),空间复杂度:O(n) ,稳定的排序算法
java代码
/**
* 从小到大排序
* @param nums
*/
public static void mergeSort(int[] nums){
int[] tmp = new int[nums.length];//作为中间数组,可以重复利用
mergeSort(nums,0,nums.length-1,tmp);
}
/**
*
* @param nums
* @param start 排序的左边界,包含
* @param end 排序的右边界,包含
*/
private static void mergeSort(int[] nums,int start,int end,int[] tmp){
if(start >= end){
return;
}
int mid = (start+end)/2;
mergeSort(nums,start,mid,tmp);
mergeSort(nums,mid+1,end,tmp);
merge(nums,start,mid,mid+1,end,tmp);
}
private static void merge(int[] nums,int s1,int e1,int s2,int e2,int[] tmp){
int index=0;
int ts1=s1,ts2=s2;
while (ts1<=e1 && ts2<=e2){
if(nums[ts1]<=nums[ts2]){
tmp[index++] = nums[ts1++];
}else{
tmp[index++] = nums[ts2++];
}
}
while (ts1<=e1){
tmp[index++] = nums[ts1++];
}
while (ts2<=e2){
tmp[index++] = nums[ts2++];
}
for(int i=0;i<index;i++){
nums[s1++]=tmp[i];//因为算法保证了传入的s1,e1,s2,e2是连续的,所以这里直接从tmp中复制过来即可,不存在中间空洞数据被覆盖的情况
}
}
快速排序
算法原理(从小到大排序):
- 从数组中选择一个基准元素,通过分割算法遍历数组,使得基准元素左边都是比基准元素小的,右边都是比基准元素大的,然后递归快排左右两部分
- 分割算法:两个索引下标分别指向数组低位与高位,low,high;low从左侧开始遍历直至碰见第一个比基准元素大的,然后high从右边开始遍历,直至碰见第一个比基准元素小的,交换两个元素,继续遍历,直至low==high
时间复杂度:O(n*log(n)),空间复杂度:O(n),是不稳定排序
java代码如下:
/**
* 从小到大排序
* @param nums
*/
public static void quickSort(int[] nums){
quickSort(nums,0,nums.length-1);
}
/**
*
* @param nums
* @param low
* @param high
*/
private static void quickSort(int[] nums,int low,int high){
if(low<high){
int index = partition(nums,low,high);
quickSort(nums,low,index);
quickSort(nums,index+1,high);
}
}
/**
* 选择中间元素为基准元素
* @param nums
* @param low 边界,包含
* @param high 边界,包含
* @return 返回基准元素或后一位的索引下标,返回后一位的情况只可能是
*/
private static int partition(int[] nums,int low,int high){
int pivot = nums[(low+high)/2];
while (true){
while (nums[low]<pivot) low++;//这里不能加上=条件,否则有可能low就越过基准元素了
while (nums[high]>pivot) high--;//同理这里不能加上=条件
if(low>=high){
return high;//要么是相邻交换最终high<low;要么是指向同一个元素,其中一边移动,最终还是high<low,所以high才是最终的分割线
}
//未越界的情况下交换
swap(nums,low++,high--);
}
}
堆排序
参考:排序算法-堆排序