1. 实验内容
使用分治和递归的思想实现二路归并排序算法
1.描述
分治法主要由两部分构成:
1)分(divide):递归解决较小的问题
2)治(conquer):然后从子问题的解构建原问题的解
分治法的三个步骤:
1)分解(Divide):将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
2)解决(Conquer):若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;
3)合并(Combine):将各个子问题的解合并为原问题的解。
2.实例
使用归并排序对一组数字按从小到大排列。
思想:
1.分而治之,将一个无序的数列一直一分为二,直到分到序列中只有一个数的时候,这个序列肯定是有序的,因为只有一个数,然后将两个只含有一个数字的序列合并为含有两个数字的有序序列,这样一直进行下去,最后就变成了一个大的有序数列
2.递归的结束条件是分到最小的序列只有一个数字的时候
2.算法流程图及说明
3.核心代码解释
#include<stdio.h>
#define max 1024
int SR[max], TR[max];
int merge(int SR[], int TR[], int s, int m, int t)//SR代表两个有序序列构成的序列,s表示起始位置,m表示两个序列的分解位置,但是SR[m]仍是属于前面一个序列,t表示结束位置
{//TR是一个空数组,用来存放排序好之后的数字
int i = s, j = m + 1, k = s;
while (i <= m && j <= t)
{
if (SR[i] < SR[j])
{
TR[k++] = SR[i++];
}
else
{
TR[k++] = SR[j++];
}
}
while (i <= m)//当前面一个序列有剩余的时候,直接把剩余数字放在TR的后面
{
TR[k++] = SR[i++];
}
while (j <= t)//当后面一个序列有剩余的时候,直接把剩余数字放在TR的后面
{
TR[k++] = SR[j++];
}
return 0;
}//该函数要求SR是由两个有序序列构成
void copy(int SR[], int TR[], int s, int t)//把TR赋给SR
{
int i;
for (i = s; i <= t; i++)
{
SR[i] = TR[i];
}
}
int mergesort(int SR[], int s, int t)
{
if (s < t)//表示从s到t有多个数字
{
int m = (s + t) / 2;//将序列一分为二
mergesort(SR, s, m);//前一半序列继续进行归并排序
mergesort(SR, m + 1, t);//后一半序列同时进行归并排序,
//以上递归调用的结束条件是s!<t,也就是进行分到只有一个数字进行归并排序的时候,一个序列只有一个数字,那么这个序列肯定是有序的
//以上都是属于“分”的阶段,目的是获得两个有序的数列
merge(SR, TR, s, m, t);//对这两个有序的数列,进行排序,变成一个同样大小但是有序的数列
copy(SR, TR, s, t);//将在TR中排序好的数列给SR,方便SR递归调用归并排序,因为每次两个归并排序的结果都是保存在TR中的,现在要进行下一步就必须在TR数列的基础上面=进行,所以我们把TR给SR
}
else//表示从s到t只有一个数字(s==t),或者没有数字(s>t)
{
;//空,也可省略,加一个else只是为了更好的理解程序
}
return 0;
}
int main()
{
int n;
printf("请输入排序数字的个数:\n");
scanf("%d", &n);
printf("请输入要排序的数字序列:\n");
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &SR[i]);
}
mergesort(SR, 0, n - 1);//升序排列
for (i = 0; i < n; i++)
{
printf("%d ", SR[i]);
}
printf("\n");
return 0;
}
4.算法复杂度分析
归并排序(Merge Sort)完全遵循上述分治法三个步骤:
1、分解:将要排序的n个元素的序列分解成两个具有n/2个元素的子序列;
2、解决:使用归并排序分别递归地排序两个子序列;
3、合并:合并两个已排序的子序列,产生原问题的解。
时间复杂度是O(NlogN)
5.测试数据及截图
6.算法优化与改进
7.心得体会
本实验使用分治和递归的思想实现二路归并排序算法,我们基本了解了分治法的思想,这样能够使问题更加容易解决。