你们好,我是阿濠,今篇内容跟你们分享的是排序算法之归并排序,很高兴分享到segmentfault与你们一块儿学习交流,初次见面请你们多多关照,一块儿学习进步.
归并排序(MERGE- SORT)是利用归并的思想实现的排序方法
,该算法采用经典的分治
( divide- and-conquer)策略
(分治法将问题分(divide)成一些小的问题而后递归求解
,而治(conquer)的阶段则将分的阶段获得的各答案修补”在一块儿
,即分而治之)。算法
1.把数组从中间划分红两个子数组
;
2.一直递归
地把子数组划分
成更小的子数组
,直到子数组
里面只有一个元素
3.依次按照递归的返回顺序
,不断地合并排好序的子数组
,直到最后把整个数组的顺序排好
。segmentfault
看看治阶段
,咱们须要将两个已经有序
的子序列合并成一个有序序列
,好比上图中的最后一次合并
,要将[4,5,7,8]和[1,2,3,6]
两个已经有序的子序列
,合并为最终序列[1,2,3,4,5,6,7,8]
,来看下实现步骤数组
//int arr[]={8,4,5,7,1,3,6,2}; //int temp[]=new int[arr.length]; //分解方法 public static void mergeSort(int[] arr, int left, int right, int[] temp) { if (left < right) { int mid = (left + right) / 2; //中间索引 //向左递归进行分解 //0 - mid 便是0 - 3 {8,4,5,7} mergeSort(arr, left, mid, temp); //向右递归进行分解 //mid+1 - midright 便是4 - 7 {1,3,6,2} mergeSort(arr, mid + 1, right, temp); } }
//合并的方法 /** * * @param arr 排序的原始数组 * @param left 左边有序序列的初始索引 * @param mid 中间索引 * @param right 右边索引 * @param temp 作中转的数组 **/ public static void merge(int[] arr, int left, int mid, int right, int[] temp) { //初始化i,左边有序序列的初始索引 int i = left; //初始化j,右边有序序列的初始索引 //为何要mid+1? //由于假设数组arr{1,3,5,6,2,4} mid=(left+right)/2 = 2 //此时左边i=left mid左边的就是 0 - mid 便是{1,3,5} //此时右边就是mid+1 - right 便是{6,2,4} int j = mid+1; int t = 0;//指向temp数组的当前索引 //(-) //先把左右两边(有序)的数据按照规则填充到temp数组 //直到左右两边的有序序列,有一边处理完毕为止 //i <= mid 表明左边有序序列有值 //j <= right 表明右边有序序列有值 while (i <= mid & j <= right) {//继续 //若是左边的有序序列的当前元素,小于等于右边有序序列的当前元素 //即将左边的当前元素,拷贝到temp数组 //假设数组arr{1,3,5,6,2,4} //左边 0 - mid 便是{1,3,5} //右边 mid+1 -right 便是{6,2,4} //若arr[i]<= arr[j] 便是1 <= 6 if (arr[i] <= arr[j]) { temp[t] = arr[i];//temp[0]=arr[i]; t += 1;//指向temp数组下一位 i += 1;//指向左边下一位arr[i+1]... }else{ //反之arr[i] >= arr[j] 左边大于右边 //则进行右边赋值给temp数组 temp[t] = arr[j];//temp[0]=arr[i]; t += 1;//指向temp数组下一位 j += 1;//指向右边边下一位arr[j+1]... } } //(二) //把有剩余数据的一边的数据依次所有填充到temp //左边的有序序列还有剩余的元素,就所有填充到temp while( i <= mid){ temp[t] = arr[i]; t += 1; i += 1; } //右边的有序序列还有剩余的元素,就所有填充到temp while( j <= right){ temp[t] = arr[j]; t += 1; j += 1; } //(三) //将temp数组的元素拷贝到arr //为何 t=0 ? //由于合并的时候按图所示数组:{8,4,5,7,1,3,6,2} //最早进入的是84 left=0 right = 1 //通过上面的左边与右边比较,得出temp数组:4,8 // 此时清空指向temp数组的下标指针t 从新回到0 //tempLeft = 0 进行将temp数组里的4,8 赋值给arr数组 t = 0; int tempLeft= left; while( tempLeft <= right){ arr[tempLeft]=temp[t]; t += 1;//赋值成功后指向temp数组的下标指针t日后移 tempLeft +=1;//84 完成后到57 此时left=2 right = 3 ... } }
//int arr[]={8,4,5,7,1,3,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; //中间索引 //向左递归进行分解 //0 - mid 便是0 - 3 {8,4,5,7} mergeSort(arr, left, mid, temp); //向右递归进行分解 //mid+1 - midright 便是4 - 7 {1,3,6,2} mergeSort(arr, mid + 1, right, temp); //进行合并 merge(arr,left,mid,right,temp); } } 运行结果以下: tempLeft:0 rigth:1 tempLeft:2 rigth:3 tempLeft:0 rigth:3 tempLeft:4 rigth:5 tempLeft:6 rigth:7 tempLeft:4 rigth:7 tempLeft:0 rigth:7 并归排序后[1, 2, 3, 4, 5, 6, 7, 8]
归并算法是一个不断递归的过程
,假设
数组的元素个数是n
。
时间复杂度是T(n)的函数: T(n) = 2*T(n/2) + O(n)
ide
对于规模为n的问题,一共要进行log(n)层
的大小切分
;每一层的合并复杂度
都是O(n)
;
因此总体的复杂度就是O(nlogn)
。函数
因为合并n个元素
须要分配一个大小为n的额外数组
,合并完成以后
,这个数组的空间就会被释放
。学习