算法学习之二:归并排序

来源:互联网 发布:c# python 编辑:程序博客网 时间:2024/06/08 14:00

归并排序的概念

将数组分为两半,将每部分递归的应用归并排序,直至不能分解为止。在两部分都排好序后,对它们进行归并。用图说明:

这里写图片描述

这里涉及到递归,有点不好理解:当将一个length为8的数组拆分为两半:左数组和右数组。只要左边数组长度不为1,就还要拆分,那就递归调用,直到长度为1,同理,右边数组也是如此的拆分。等拆分好的数组长度都是为1的时候,就开始两两数组排序合并。

算法的具体实现:

public class MeargeSort {    public static void meargeSort(int[] list){        //如果数组中的长度还大于1(说明没有切分长最小单位,那就还需要再次拆分)        if(list.length>1){            int[] firstHalf = new int[list.length/2];//拆分成左半部分数组            System.arraycopy(list,0,firstHalf,0,list.length/2);//给firstHalf赋值            meargeSort(firstHalf);//递归调用,直至将左边数组都拆分成最小单位            int secondHalfLength = list.length-list.length/2;            int[] secondHalf = new int[secondHalfLength];//拆分右半部分的数组            System.arraycopy(list,list.length/2,secondHalf,0,secondHalfLength);//给secondHalf赋值            meargeSort(secondHalf);//递归调用,直至将右边数组都拆分成最小单位            //经过以上递归的操作,firstHalf和secondHalf都是拆分好了的数组,开始排序            int[] result = sort(firstHalf,secondHalf);            System.arraycopy(result,0,list,0,result.length);        }    }    private static int[] sort(int[] firstHalf, int[] secondHalf) {        //准备3个指针,第一个指针指向firstHalf起始位置,第二个指针指向secondHalf起始位置        //第三个指针指向一个临时数组(将firstHalf和secondHalf要合并而成的数组)起始位置        int currentIndex1 = 0;        int currentIndex2 = 0;        int currentIndex3 = 0;        int[] temp = new int[firstHalf.length+secondHalf.length];        //只要指针都没有指向末尾位置,就不断比较        while(currentIndex1<firstHalf.length&&currentIndex2<secondHalf.length){            if(firstHalf[currentIndex1]<secondHalf[currentIndex2]){//firstHalf元素小                temp[currentIndex3++] = firstHalf[currentIndex1++];//temp中就放置小的元素            }else{                temp[currentIndex3++] = secondHalf[currentIndex2++];            }        }        //以上比较完之后,有可能firstHalf还有元素没有比较到或是secondHalf中的元素还有没有比较到的        while(currentIndex1<firstHalf.length){            //将firtshalf中剩余的元素都复制到temp中;            temp[currentIndex3++] = firstHalf[currentIndex1++];        }        while(currentIndex2<secondHalf.length){            //secondHalf中剩余的元素都复制到temp中;            temp[currentIndex3++] = secondHalf[currentIndex2++];        }        return temp;    }}

测试看下结果:

int[] list2 ={5,3,8,2,4,1,6,7}; MeargeSort.meargeSort(list2);        for(int i = 0;i<list2.length;i++){            Log.e("hxy",list2[i]+"   ");        }

从打印台可以看到list2 是一个已经排好序的数组{1, 2 ,3 ,4 ,5 , 6 , 7 , 8}。

MeargeSort 类中疑难杂点分析:

1. sort方法分析:看看是如何将已经排序好的数组合并为一个数组

以下图示例:三个指针都指向初始化位置,两两比较,哪个元素小,就先放置在temp中,同时被拿取的元素的指针+1,没有拿取的元素位置不变,重复比较操作,直到有一个或是2个数组的指针指向元素末尾处。

大家可能看不清楚数组中的数字( 第一个数组2,3,5,8 第二个数组: 1, 4 ,6 ,7 , 9 ),按照指针位置比较和移动,就一目了然了。

这里写图片描述

最后如果数组1或是2中还有剩余元素,直接复制到temp中。

这里写图片描述

2. 递归处分析:

先看如下代码 :左边数组的递归调用
我用文字说明下:

(1) 判断数组长度,如果长度大于1,将数组分为A0数组,A1数组。
(2) 继续判断A0长度,如果还是大于1.将A0分为A01,A02
(3)假设在n次分割之后,某个分组的长度最终为1了,此时不再递归调用。
   public static void meargeSort(int[] list){        //如果数组中的长度还大于1(说明没有切分长最小单位,那就还需要再次拆分)        if(list.length>1){            int[] firstHalf = new int[list.length/2];//拆分成左半部分数组            System.arraycopy(list,0,firstHalf,0,list.length/2);//给firstHalf赋值            meargeSort(firstHalf);//递归调用,直至将左边数组都拆分成最小单位   ..................}
(4)再看下面的代码:是对右边分组的递归调用,和左边分组过程是一样的。
 public static void meargeSort(int[] list){        int secondHalfLength = list.length-list.length/2;        int[] secondHalf = new int[secondHalfLength];//拆分右半部分的数组        System.arraycopy(list,list.length/2,secondHalf,0,secondHalfLength);//给secondHalf赋值         meargeSort(secondHalf);//递归调用,直至将右边数组都拆分成最小单位.................}
(5)对拆分为最小单位的小分组排序。所以,经过递归分解,和排序 ,firstHalf,secondHalf最终都会是排序好的。整合这两者之后,完成排序。
int[] result = sort(firstHalf,secondHalf);
0 0