一、基本思想
归并排序:采用了分治策略(将问题分解成一些小问题,再逐个递归求解,最后再将各阶段的结果“修补”到一起)。
思路分析:
归并排序使用分治法(将问题分成一些小的问题然后递归求解),通过 “分解-合并-复制” 的步骤,将一组数排序。
- 分解:将一组数从中间分成两份,再将每一份分成两份,直到每一份只有一个数;
- 合并:通过一个temp临时数组,合并相邻有序子序列;
(1)在待合并的两个有序子序列起始位置分别加一个指针,比较指针所指位置的数,将较小的数存入temp数组后,将那个指针向后移动,再比较大小将较小的数存入temp;
(2)如果待合并的两个有序子序列中,有一组已经被全部添加到temp中了,那么将另一组中的剩余数顺序存入temp中; - 复制:将临时数组中排好序的数再复制到原数组中;
二、代码实现
package sort;
import java.util.Arrays;
import java.util.Date;
/**
* 归并排序
*
* 思路分析:
* 归并排序使用分治法(将问题分成一些小的问题然后递归求解),通过 "分解-合并-复制" 的步骤,将一组数排序。
* 分解:将一组数从中间分成两份,再将每一份分成两份,直到每一份只有一个数;
* 合并:通过一个temp临时数组,合并相邻有序子序列;
* (1)在待合并的两个有序子序列起始位置分别加一个指针,比较指针所指位置的数,将较小的数存入temp数组后,将那个指针向后移动,再比较大小将较小的数存入temp;
* (2)如果待合并的两个有序子序列中,有一组已经被全部添加到temp中了,那么将另一组中的剩余数顺序存入temp中;
* 复制:将临时数组中排好序的数再复制到原数组中;
*/
public class MergeSort {
public static void main(String[] args) {
int[] arr = {8,4,5,3,1,7,6,2};
int[] temp = new int[arr.length];
mergeSort(arr,0,arr.length-1,temp);
System.out.println(Arrays.toString(arr));
}
public static void mergeSort(int[] arr,int left,int right,int[] temp){
//先分解 后合并
if(left<right){
int mid = (left+right)/2;
mergeSort(arr,left,mid,temp);
mergeSort(arr,mid+1,right,temp);
merge(arr,left,right,mid,temp);
}
}
/**
* 合并两个有序列表
* @param arr
* @param left
* @param right
* @param mid
* @param temp
*/
public static void merge(int[] arr,int left,int right,int mid,int[] temp){
int i = left;//左边序列的初始索引位置
int j = mid+1;//右边序列的初始索引位置
int t=0;//指向temp数组中的当前位置
//第一步:
//将待合并的两个有序序列从左到右比较大小并按照顺序存入temp中
while(i<=mid && j<=right){
if(arr[i]<arr[j]){
temp[t] = arr[i];
t++;
i++;
}else{
temp[t] = arr[j];
t++;
j++;
}
}
//第二步:
//将有剩余的序列里边的元素顺序添加到temp中
while (i<=mid){
temp[t] = arr[i];
t++;
i++;
}
while (j<=right){
temp[t] = arr[j];
t++;
j++;
}
//第三步:
//将temp中的数复制到愿数组 arr 中。注意:不是每次复制都从 arr原数组的第一个元素开始写,也不是每次复制都复制都对原数组的所有元素写。
//每一次复制的元素写入时,从当前合并序列的left索引开始写入arr。
t = 0;
int tempLeft = left;//tempLeft指向写入arr原数组时的索引位置。即:每次写入的位置是left到right所在索引之间。tempLeft用于向后移动。
while(tempLeft <= right ){
arr[tempLeft] = temp[t];
tempLeft++;
t++;
}
}
}
三、性能对比
以80000个数据测试,耗时大约11ms