活动地址:CSDN21天学习挑战赛
归并排序是多次将两个或两个以上的有序表合并成一个新的有序表,最简单的归并是将两个有序的子表合并成一个有序的表,即二路归并;
- 归并排序的基本思想是分治法;
- 归并排序做的第一件事是将一个长序列分割成两部分(这里是二路归并),然后将分割出来的两部分继续各自看为一个序列再进行分割,以此循环直至分割成只存在一个元素的序列为止;
- 分割完后再将序列两两进行配对,从小到大进行排序,排序完生成一个新的序列再跟另外配对完的序列进行配对排序,依次循环直至将所有的元素合成至一个序列;
- 当合并成一个序列的时候,整个序列呈有序状态;
- 将待排序序列存入数组;
- 建立一个方法,方法内有三个参数,一个是待排序的数组,一个是起始坐标,一个是终点坐标;
- 如果起始坐标不小于终点坐标,那么代表已经拆分为一个元素一个序列的程度了,故直接返回;
- 声明一个变量记录中间位置的坐标,即(起始坐标 + 终点坐标)/ 2 ;( 右移一个位置也相当于除二,只是写法不同,意义一样 )
- 进行拆分序列,拆分方式:递归本方法两次,一次传入左边区间的序列,即起始坐标到中间位置的坐标范围,一次传入右边区间的序列,即中间位置坐标 + 1 到终点坐标的范围;
- 在递归调用的后面调用一个方法,功能是排序;
- 该方法的参数有四个,一个是待排序数组,一个是起始坐标,一个是中间位置坐标,一个是终点坐标;
- 建立一个辅助数组,长度为待排序元素的长度;
- 建立一个变量存储起始坐标,即左边序列的起始坐标;
- 建立一个变量存储中间位置坐标 + 1 ,即右边序列的起始坐标;
- 建立一个变量表示辅助数组的起始坐标;
- 将左边区间的元素依次和右边区间元素进行对比;
- 对比出来将较小的元素优先放入辅助数组直到某一个序列坐标超出;
- 再对两个序列进行判断,如果未超过区间的最大坐标表示未遍历完,则将未参与遍历的元素依次放入辅助数组;( 值得注意的是,每一个进入判断的两个序列都是相对有序的,因为递归的性质是由下至上的,也就是说两个区间要么是单个元素,要么就是一个已经排序过的区间 )
- 最后将辅助数组拷贝到待排序数组的相应位置即可;(也可以自己写一个 for 循环进行拷贝)
- 在每一次调用完排序方法后将数组打印出来;
- 根据每一次的排序结果我们可以看到归并排序的每一次过程;
- 虽然说分治算法原理是两个或多个支路同时进行,但是从每一次的运行结果来看,分治法在实际运用上是将一个支路探测完毕才进行下一个支路的探测;
public class test {
public static void main(String[] args) {
int[] arr = { 20 , 15 , 12 , 9 , 18 , 16 , 10 , 8 };
mergeSort(arr,0,arr.length-1);
for ( int e : arr ) {
System.out.print( e + " ");
}
}
public static void mergeSort( int[] arr ,int left ,int right ) {
if ( left >= right )
return;
int mid = (left + right) >> 1;
mergeSort(arr, left , mid);
mergeSort(arr, mid+1,right);
sort(arr,left,mid,right);
}
public static void sort( int[] arr, int left,int mid,int right ){
int[] temp = new int[right-left+1];
int i = left;
int j = mid + 1;
int t = 0;
while ( i <= mid && j <= right ){
if ( arr[i] < arr[j] )
temp[t++] = arr[i++];
else
temp[t++] = arr[j++];
}
while ( i <= mid )
temp[t++] = arr[i++];
while ( j <= right )
temp[t++] = arr[j++];
System.arraycopy(temp, 0, arr, left, temp.length);
}
}