归并排序 O(Nlogn)
归并排序的思路是:将要排序的数组先递归分为一个一个的,长度为1的小数组,再通过递归合并起来,在合并的过程中,先开辟一个新的数组空间,通过同时遍历两个老数组的每个元素(此时两个数组已经是有序的了),不断地给新空间赋值来达到重新排序的效果。可以理解为变交换元素为赋值,再加上递归来实现。
package cn.stu.test;
import java.util.Arrays;
public class Test{
public static void merge(int[] arr,int left,int mid,int right){
int[] arr_temp = new int[arr.length];//此处也可以赋值数组长度为(right-left+1)
int left_temp = left;
int mid_temp = mid;
int i = 0;
while((left_temp<=mid)&&(mid_temp+1<=right)){
if(arr[left_temp] > arr[mid_temp+1]){
arr_temp[i] = arr[left_temp];
i++;
left_temp++;
}else{
arr_temp[i] = arr[mid_temp+1];
i++;
mid_temp++;
}
}
while(left_temp<=mid){
arr_temp[i] = arr[left_temp];
i++;
left_temp++;
}
while(mid_temp+1<=right){
arr_temp[i] = arr[mid_temp+1];
i++;
mid_temp++;
}
for(int j=0;j<i;j++){
arr[left+j] = arr_temp[j];
}
}
public static void sort_merge (int[] arr,int left,int right){
if(left<right){
int temp =(left+right)/2;//left和right太大时要防止越界
sort_merge(arr,left,temp);
sort_merge(arr,temp+1,right);
merge(arr,left,temp,right);
}
}
public static void main(String[] args) {
int[] arr_temp = {1,3,4,2,9,5,43,5,6,7,44};
sort_merge(arr_temp,0,arr_temp.length-1);
System.out.println(Arrays.toString(arr_temp));
}
}
改进的递归排序:
方法一:
将sort_merge方法改为如下的方式,就是加上一个判断,通过这个判断在适当的时候(就是要进行排序的子数组是有序的时候)可以直接跳过去,从而提高效率
public static void sort_merge (int[] arr,int left,int right){
if(left<right){
int temp =(left+right)/2;//left和right太大时要防止越界
sort_merge(arr,left,temp);
sort_merge(arr,temp+1,right);
if(arr[temp] < arr[temp+1])
merge(arr,left,temp,right);
}
}
方法二:
基于插入排序对于小规模数组的排序更具优势,所以我们可以采用归并加上插入的方式,先递归,将大数组分为一些小数组,再通过插入来处理,最后再通过递归合起来。
public static void sort_merge(int[] arr, int left, int right) {
if (left < right) {
if(right-left <= 5){//5是自己设置的,根据实际情况改变
sort_insert(arr, left, right);
return;
}
int temp = (left + right) / 2;// left和right太大时要防止越界
sort_merge(arr, left, temp);
sort_merge(arr, temp + 1, right);
if (arr[temp] < arr[temp + 1])
merge(arr, left, temp, right);
}
}
插入排序的代码如下所示:
public static void sort_insert(int[] arr, int left, int right) {
for (int i = left + 1; i <= right; i++) {
int j = i;
while ((j >= left + 1) && (arr[j] > arr[j - 1])) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
j--;
}
}
}
以上的归并排序采用的是自顶向下的排序方式,也可以采用自底向上的排序方式,跳过将数组拆分的步骤,直接从一个一个的小数组的合并开始。
public static void sortMergeDownToUp(int[] arr){
for(int i=1;i<=arr.length;i+=i){
for(int j=0;j<arr.length-i;j+=i+i){
merge(arr, j, j+i-1, Math.min(j+2*i-1, arr.length-1));
}
}
}
外循环从1,2,4,8,16….开始逐次合并小数组;
内循环注意循环的增量不大一样,还有要注意防止数组越界,例如判断条件和合并的最右值都要额外考虑;