排序五 归并排序

今天我给大家介绍排序中的最后一个排序---归并排序,归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用

  既然提到分治法这里我就对分治法进行一个简单的介绍:

分治法可以通俗的解释为:把一片领土分解,分解为若干块小部分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化。

分治法的精髓:

分--将问题分解为规模更小的子问题;

治--将这些规模更小的子问题逐个击破;

合--将已解决的子问题合并,最终得出“母”问题的解;

其实理解起来很简单,就是把我们的大问题不断你的划分成小问题,然后将小问题解决之后,小问题解决之后大问题也就相应的解决了。

  这里我们拿一个数组来模拟一次归并排序。

 

首先要做到的是分,将你的数组分成最小的子问题。

然后开始治。

 

这次我的排序为升序,所以让所有不符合小集合都调整过来让所有小集合都是升序的。

 

然后继续两两合并,同样要求是升序的。

 

 

再下一次合并的时候整个数组都是有序的了。

 

下边用代码给大家解释一下归并排序的实现

void Merge_sort(int A[], int N)

{

int *Temp = (int *)malloc(N*sizeof(int));

if (Temp)

{

MSort(A, Temp, 0, N - 1);

free(Temp);

}

else

printf("no space!\n");

}

 

首先这里归并排序和其他排序是有一定的区别的,这里其他排序是在原数组的基础上直接调动的,但是归并排序是需要创建一个新的数组,将归并的数据放到新的数组中上边的函数就是用来创建一个数组,然后将创建好之后的数组和以前的数组以及要排序的区间作为参数传入。其实这里我想过要将这个创建数组的语句和之后的函数融到一起,但是这样在传参的时候会有些不方便所以这里将创建新的数组单独拿出来之后,四个参数传入排序的函数。

void MSort(int A[], int Temp[], int L, int RightEnd)

{

int center;

if (L<RightEnd)

{

center = (L + RightEnd) / 2;

MSort(A, Temp, L, center);

MSort(A, Temp, center + 1, RightEnd);

Merge(A, Temp, L, center + 1, RightEnd);

}

}

这里是排序的函数,首先不断的将你的数组不断你的划分,这里还要明白一个小细节。

 

当我们拿到数组的时候,是怎么来划分的,划分的时候是按照我写的数组的顺序1,2,3,4,5,6,7来划分的吗?并不是,

 

相信大家都能看到这个顺序的原因,递归是不断的不断的走到最底层才一点的一点往回退。和二叉树是一样的,首先不断的往左往左走到最后边才开始往右走。

每一段数据都需要先排左半部分,右半部分然后进行归并,这里相对复杂的是归并函数。

void Merge(int A[], int Temp[], int L, int R, int RightEnd)//合并两个有序序列

{

int LeftEnd = R - 1;

int p = L, i;

int num = RightEnd - L + 1;//计算数组中所有数据的个数

while (L <= LeftEnd&&R <= RightEnd)

if (A[L] <= A[R])

Temp[p++] = A[L++];

else

Temp[p++] = A[R++];

while (L <= LeftEnd)

Temp[p++] = A[L++];

while (R <= RightEnd)

Temp[p++] = A[R++];

for (i = 0; i<num; i++, RightEnd--)

A[RightEnd] = Temp[RightEnd];

}

这里是需要五个参数的,a是原数组也就是保存原始数据的,temp是需要归并到的数组,然后是两个区间的范围,两个区间需要三个数据,左边,左边的结尾同时也是右边的开始,右边的结尾三个数据下标。

拿到下标之后开始判断,这里是拍的升序,从你的左区间第一个和右区间第一个开始找,如果左边小那就让左边的数据放到temp里边,如果不是那就让右区间的数据放到temp数组里边。存在一种情况是左边的所有都比右边的任何一个数据要小,这时候左边的数据放到temp里边的时候右边数据一个都还没有放到temp里边这时候就需要将你的右边的数据放进去,当然也不排除右边都进去了,左边还没进去,所以这下边两个while循环是来解决我上边所说的情况。

当排序结束之后,还需要将你的temp数组写入到a数组里边一一对应过去即可。

这时候排序就结束了。归并排序思想并不难,但是实现起来还是需要拐弯抹角,因为不能在你原来数组上直接改数据,这样可能会覆盖其他还没有处理的数据。所以就需要一个新的数组来对其进行操作。

 这里,就对所有的基本排序有了一些基本的介绍,之后我会给大家总结一篇排序的比较和分析。

猜你喜欢

转载自blog.csdn.net/Hanani_Jia/article/details/80632153