归并排序以及时间复杂度,稳定性分析

    在理解归并排序之前先要理解算法中一个非常重要的思想方法:分冶模式。

算法导论中分冶策略定义:将原问题划分为n个规模较小,与原问题结构相似的子问题;递归解决这些子问题,然后再合并其结果,就得到原问题的解。

分冶模式三大步骤:

1,分解:将原问题分解为规模较小的n个子问题;

2,解决:递归得解决个子问题,若子问题足够小,则直接求解;

3,合并:将子问题合并为原问题的解;

理解了分冶模式之后,再理解一个归并排序中利用到分冶模式的一个非要重要的步骤:合并排序;

合并排序三个基本步骤:

1,将待排序数组分解为各含n/2个元素的子数组;

2,将两个子数组排序好;

3,将已排序好的子数组合并,得到排序最后的结果;

由于算法导论中的伪代码翻译成的java代码太过啰嗦,这里我们提供一个比较好理解,没有用到哨兵元素的版本,其步骤都差不多;

合并排序代码(java版本):

package sfdl2_1_4;


public class MergeSortion {

public static void merge(int[] arr,int p,int q,int r){
int[] help = new int[r-p+1];
int i = 0;
int p1 = p;
int p2 = q+1;
while(p1<=q&&p2<=r){
help[i++] = arr[p1] }
while(p1<=q){
help[i++] = arr[p1++];
}
while(p2<=r){
help[i++] = arr[p2++];
}
for(int j = 0;j arr[p+j] = help[j];
}
}
public static void main(String[] args) {
int[] arr = {1,3,5,7,9,2,4,6,8,10};
merge(arr,0,4,9);
for(int i = 0;i System.out.print(arr[i]+" ");
}
}
}

以上为合并排序的代码,其主要的思想是,建立一个和待排序数组大小一样的辅助数组,将待排序的数组分为两个部分,然后再两个子数组中分别建立一个指针,每次比较子数组中指针所指位置的元素的大小,若元素较小,则将较小的元素复制至辅助数组中,然后指针前移一位,若有一个指针移动到了子数组的末尾,则将另外一个子数组的全部元素都复制至辅助数组中;

另:实现上述操作的前提是,分好的子数组有序;

合并排序涉及到n个元素的比较和移动,明显的时间复杂度为O(n);因为可以再比较的时候可以加上条件限制相同的元素是否移动,所以合并排序是具有稳定性的排序。

理解完了合并排序就可以很轻松的写出归并排序的代码了

归并排序代码:

package sfdl2_1_4;


public class MergeSortion {

public static void merge(int[] arr,int p,int q,int r){
int[] help = new int[r-p+1];
int i = 0;
int p1 = p;
int p2 = q+1;
while(p1<=q&&p2<=r){
help[i++] = arr[p1] }
while(p1<=q){
help[i++] = arr[p1++];
}
while(p2<=r){
help[i++] = arr[p2++];
}
for(int j = 0;j arr[p+j] = help[j];
}
}

public static void mergeSort(int[] arr,int p,int r){
int q = p+((r-p)>>2);
//base case
if(p>=r){
return;
}
mergeSort(arr,p,q);
mergeSort(arr,q+1,r);
merge(arr,p,q,r);
}

public static void mergeSort(int[] arr){
mergeSort(arr,0,arr.length-1);
}
public static void main(String[] args) {
int[] arr = {1,3,5,7,9,2,4,6,8,10};
mergeSort(arr);
for(int i = 0;i System.out.print(arr[i]+" ");
}
}
}

再归并排序的核心步骤中,正是上面已经写过的合并排序的代码;在这里我们只不过是利用了递归的思想,将数组每一次都分解为原来的一半大小的两个子数组,当分解到了右边界比左边界还大的时候,不再分解,开始排序。然后将排序好的子数组逐级合并,最后得到的结果就是排序好的数组;

归并排序时间复杂度分析(不用master定理推倒):

原数组的长度为n,则细分得最大深度为log(n),每一层需要排序的元素为n;则归并排序的时间复杂度为O(nlog(n));

稳定性:因为交换元素时,可以在相等的情况下做出不移动的限制,所以归并排序是可以稳定的;



你可能感兴趣的:(算法Java)