PAT A1089/B1035 Insert or Merge
一、题意:
给出一个原始数列和一个经排序后的数列,判断是插入排序还是归并排序,并输出下一步排序后的数列。
分析:
要确定所给定的数列是插入排序后还是归并排序,需要将每次排序后的数列与原始数列比较,如果一样,则再经过一次排序即可。注意:这里如果给的两次都是原始数列,可能会有两种结果。如 3 4 2 1
3 4 2 1
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 111;
int origin[N], tempOri[N], changed[N];
int n;
bool isSame(int A[], int B[])
{
for(int i = 0; i < n; i++)
{
if(A[i] != B[i])
return false;
}
return true;
}
void showArray(int A[])
{
for(int i = 0; i < n; i++)
{
printf("%d", A[i]);
if(i < n-1)
printf(" ");
}
printf("\n");
}
bool insertSort()
{
bool flag = false;
for(int i = 1; i < n; i++)
{
if(i != 1 && isSame(tempOri, changed))
flag = true;//每次都样比较与目的数列是否一样
int j = i, temp = tempOri[i];
while(tempOri[j-1] > temp)
{
tempOri[j] = tempOri[j-1];
j--;
}
tempOri[j] = temp;
if(flag == true)
return true;
}
return false;
}
void mergeSort()
{
bool flag = false;
for(int step = 2; step/2 <= n; step *= 2)
{
if(step != 2 && isSame(tempOri, changed))
flag = true;
for(int i = 0; i < n; i += step)
{
sort(tempOri + i, tempOri + min(i+step, n));
}
if(flag == true)
{
showArray(tempOri);
return;
}
}
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &origin[i]);
for(int i = 0; i < n; i++)
scanf("%d", &changed[i]);
for(int i = 0; i < n; i++)
{
tempOri[i] = origin[i];
}
if(insertSort())
{
printf("Insertion Sort\n");
showArray(tempOri);
}
else
{
for(int i = 0; i < n; i++)
{
tempOri[i] = origin[i];
}
printf("Merge Sort\n");
mergeSort();
}
return 0;
}
二、归并排序:
首先将数列两两分组,然后组内排序。之后再左右之间的分组组合在一起,再进行组内排序,直至分组长度大于等于数列长度。
1.递归实现:
const int maxn = 100;
void Merge(int A[], int L1, int R1, int L2, int R2)
{
int i = L1, j = L2;
int temp[maxn], index = 0;
while(i <= R1 && j <= R2)
{
if(A[i] < A[j])
temp[index++] = A[i++];
if(A[i] >= A[j])
temp[index++] = A[j++];
}
while(i <= R1)
temp[index++] = A[i++];
while(i <= R2)
temp[index++] = A[j++];
}
void MergeSort(int A[], int left, int right)
{
if(left < right)
{
int mid = (left + right)/2;
MergeSort(A, left, mid);
MergeSort(A, mid+1, right);
Merge(A, left, mid, mid+1, right);
}
}
2.非递归实现
void MergeSort(int A[], int left, int right)
{
for(int step = 2; step /2 <= n; step *= 2)
{//这里为step/2是因为当step = 2n的时候是整个数列(左子列)内的排序,而step = n的时候是对整个数列分成两分的左右子列分别排序
for(int i = 0; i < n; i += step)
{
int mid = i + step/2-1;
merge(A, i, mid, mid+1, mid+ min(i+step-1, n));
}//这里i+step-1是为了防止越界
}
}
为了方便,这里也可以直接用sort函数来代替merge函数。
三、插入排序
每次选出数列中的一个数,并按大小关系插入已经排好的部分数列中。
void insertSort(int A[])
{
for(int i = 1; i < n; i++)//下标为0~n
{
int temp = A[i], j = i;//用一个数来暂时保存要排序的数的副本和下标,因为前面的数字有可能比它大,所以前面的数字可能会往后挪导致当前的数字可能被覆盖
while(temp < A[j])
{
A[j] = A[j-1];
j--;
}
A[j] = temp;//排序完后将原先要排序的数字放入属于它的位置
}
}
三、选择排序
每次从数列中选出一个最小的数字,将其与最前面未排序的数字交换。
void SelectSort(int A[], int n)
{
int temp, k;
for(int i = 0; i < n-1; i++)
{
k = i;
for(int j = i; j < n; j++)
{
if(A[j] < A[k])
{
A[k] = A[j];
k = j;
}
temp = A[k];
A[k] = A[i];
A[i] = temp;
}
}
}