您的位置:首页 > 其它

PAT : 1035. 插入与归并(25)

2015-03-31 18:27 330 查看
根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成N个只包含1个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下1个有序的序列。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数N (<=100);随后一行给出原始序列的N个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:
首先在第1行中输出“Insertion Sort”表示插入排序、或“Merge Sort”表示归并排序;然后在第2行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行末不得有多余空格。

输入样例1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

输出样例1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0

输入样例2:
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

输出样例2:
Merge Sort
1 2 3 8 4 5 7 9 0 6

很多人都用的是实现两个算法,之后去比对的方法,我不打算这么做,我想应该能够识别这两种算法产生的序列的特征,简单来说,插入排序就是前一段有序,后一段不一定有序,归并排序就是一段一段的数各自有序,但是在识别归并排序的时候没想到一个点让我吃了大亏。因为段与段之间可能也是有序的,就是说比如段长为2,但也许某相邻的若干个段连起来也是有序的,这样递增的段长就成了4或者更大,这给识别就造成了难度,我原以为只要求出每个递增段的段长,如果每个段的长度都相等(排除最后一段,因为最后一段可能不足一段的段长)就是归并,现在想来真是图样图森破。好在http://blog.csdn.net/fang_abc/article/details/44113969给我了启发,非常感谢。他的思想就是拿到第一段递增段的长度,将这个长度作为步长,将数列分为k个段,看这每个段是否全部有序,如果不是,段长除以2重复以上过程。这里我觉得原帖有一个漏洞,如果第一个递增段长为6,即由3个段长为2的段拼接成,每次除2会出问题,于是我在最前面加了一个判断,判断第一个递增段长是否是2的指数,如果是,继续,如果不是,直接设置段长为2

关于判断是否为2的指数的函数func(),原理是i(设i为2的指数)与i-1的二进制按位与的结果是0,如8的二进制数为1000,7为0111,按位与的结果即为0

#include <cstdio>
#include <cstdlib>
#include <algorithm>

using namespace std;

bool issorted (int *numList, int length)
{
for(int i = 1; i < length; i++)
{
if(numList[i] < numList[i-1])
return false;
}
return true;
}

int func(int i)
{
return ((i > 0) && ((i & (i - 1)) == 0));
}

int main()
{
int flag = 0, seqlength = 1;
int n;
scanf("%d", &n);
int *numList = (int *) malloc (n * sizeof(int));
int *ul = (int *) malloc (n * sizeof(int));

int i;
for(i = 0; i < n; i++)
scanf("%d", &ul[i]);

for(i = 0; i < n; i++)
{
scanf("%d", &numList[i]);
if(i >= 1)
{
if(numList[i] >= numList[i-1] && flag == 0)
seqlength++;
else
flag = 1;
}
}

int sortlength = seqlength;

sort(ul, ul+seqlength);
for(i = 0; i < n; i++)
if(ul[i] != numList[i])
break;

if(i == n)
flag = 1;

else
{
flag = 0;
int allpass = 0;
if(! func(sortlength))
sortlength = 2;

else
{
while(sortlength >= 2 && allpass == 0)
{
allpass = 1;
int k = n / sortlength;
for(i = 0; i < k; i++)
if(! issorted(numList+i*sortlength, sortlength))
{
allpass = 0;
break;
}

if(! issorted(numList+k*sortlength, n-k*sortlength))
allpass = 0;

if(allpass == 0)
sortlength /= 2;
}
}
}

if(flag == 0)
{
printf("Merge Sort\n");
int step = sortlength*2;
if(step >= n)
sort(numList, numList+n);
else
{
int k = n/step;
for(i = 0; i < k; i++)
sort(numList+i*step, numList+(i+1)*step);
if(n % step != 0)
sort(numList+k*step, numList+n);
}
}
else
{
printf("Insertion Sort\n");
sort(numList, numList+seqlength+1);
}

for(i = 0; i < n; i++)
{
printf("%d", numList[i]);
if(i < n - 1)
printf(" ");
}
printf("\n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: