1 概述
归并排序是指利用归并操作的一种排序方法。规定是指将两个或两个以上的有序表组合成一个新的有序表的过程。
2 基本思想
归并排序的基本思想是将n个元素的初始序列看成n个成都为1的子序列,两两归并,得到n/2个长度为2或1的子序列,再两两归并,直到得到一个长度为n的有序序列为止。归并排序的核心操作时归并,而整个归并排序的处理过程可用递归方式完成。
具体原理如下:
1)有一数组如下,我们使用归并排序对其进行排序,首先将数组分成两个子序列,n/2;
2)这个时候我们就会想,如果把左边子序列和右边子序列各自都排好序,然后一合并是不是就可以了呢!那么怎么排呢,是不是可以同样参照上面的做法,把左边子序列又分成两个小的子序列呢,左边如此,右边也一样,如下图:
3)是不是可以重复第2)步呢,直到每一个小的子序列都只有一个元素,如下图:
4)然后此时,对每一个小的子序列,我们就不需要对其进行排序了,只需要对每两个子序列进行归并即可,即,将两个有序的序列进行归并然后放回原数组中。
5)重复第4步,直到结束
3 如何归并
也就是如何将两个有序的序列合并成一个序列并放回原数组,步骤如下:
假设现在需要合并数组 p 中 i 位置到j位置,j+1 位置到 k 位置的两个序列。
1)建立一个空数组,temp,长度为k-i+1;
2)首先,两个不同的指针指向两个序列的首位,然后比较两个元素的大小,如果第一个序列中的元素不大于第二个序列中的元素,那么将这个元素添加到temp中,同时指向第一个序列的指针向后移动一位,指向第二个序列的指针保持不动;
3)重复第2)步,直到两个序列中的某一个序列元素遍历结束;
4)上述步骤走完,应该会有其中一个序列是还剩下元素的,然后直接添加到temp后面即可。
5)将temp中元素放回原数组。
4 代码演示
// 先进的排序方法
// 归并排序
#include<stdio.h>
int main()
{
int arr[]={47,34,66,100,70,19,22,47},*p=arr;
int i,j,len;
printf("请将以下数据升序排列!\n");
len = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<len;i++){
printf("%-4d",*(arr+i));
}
void mergesort(int *p,int s,int t);
mergesort(p,1,len);
printf("\n排序后的序列如下!\n");
for(i=0;i<len;i++){
printf("%-4d",*(p+i));
}
return 0;
}
void merge(int *p, int i, int j, int k) // 合并p中i位置到j位置,j+1位置到k位置的两个数组
{
int m=i-1,n=j; // 因为i,j,k代表的是位置,真正索引的时候应该是位置减去1;
int temp[k-i+1],l=0; // temp是一个临时的空数组,l是用来记录数组的
for(;m<j && n<k;l++){ // 因为每循环一次,都会往temp中增加一个数
if(p[m]<=p[n]){
temp[l]=p[m];
m++;
}else{
temp[l]=p[n];
n++;
}
}
// 因为上述循环走完,应该会有其中一个数组是还剩下元素的,直接添加到temp后面即可
while(m<j){
temp[l++]=p[m++];
}
while(n<k){
temp[l++]=p[n++];
}
// 做完以后,将temp放回p对应的i到k位置中
for(m=i-1;m<k;m++){
p[m]=temp[m-i+1];
}
}
void mergesort(int *p,int s,int t)
{
if(s<t){
int m=(s+t)/2; // 分治
mergesort(p,s,m); // 左分且归并
mergesort(p,m+1,t); // 右分且归并
merge(p,s,m,t);
}
}