09-排序1 排序 (25 分)
给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。
本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:
数据1:只有1个元素;
数据2:11个不相同的整数,测试基本正确性;
数据3:103个随机整数;
数据4:104个随机整数;
数据5:105个随机整数;
数据6:105个顺序整数;
数据7:105个逆序整数;
数据8:105个基本有序的整数;
数据9:105个随机正整数,每个数字不超过1000。
输入格式:
输入第一行给出正整数N(≤10^5 ),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。
输出格式:
在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。
输入样例:
11
4 981 10 -17 0 -20 29 50 8 43 -5
输出样例:
-20 -17 -5 0 4 8 10 29 43 50 981
代码
递归方法使用的是MergeSort()方法,非递归方法使用的是MergeSort2()方法。非递归方法有部分细节加了注释,还有一部分地方是一开始写错的,被我注释掉了。
#include<iostream>
#define MaxSize 100000
int a[MaxSize];
using namespace std;
void GetData(int a[], int N) {
for (int i = 0; i < N; i++) {
cin >> a[i];//这里数据不需要后移
}
}
void DispArr(int a[], int N) {
cout << a[0];
N--;
int i = 1;
while (N--) {
cout << " " << a[i++];
}
}
void Merge(int a[],int tmpa[], int L, int R, int RightEnd) {
/*将数组a[]中的数据,在有序区间a[L,R-1]和a[R,RightEnd]进行归并,然后存放到tmpa[]中,最终存回a[]*/
int LeftEnd = R - 1;
int tptr = L;
int start = L;
while (L <= LeftEnd&&R <=RightEnd) {
if (a[L] > a[R]) tmpa[tptr++] = a[R++];
else
tmpa[tptr++] = a[L++];
}
while (L <= LeftEnd)//这里不能写为while(L!=LeftEnd),当L=1,LeftEnd=0的时候会导致泄露
tmpa[tptr++] = a[L++];
while (R <= RightEnd)
tmpa[tptr++] = a[R++];
for(int i=start;i<=RightEnd;i++){
a[i] = tmpa[i];
}
}
void Merge2(int a[], int tmpa[], int L, int R, int RightEnd) {
/*将数组a[]中的数据,在有序区间a[L,R-1]和a[R,RightEnd]进行归并,然后存放到tmpa[]中*/
int LeftEnd = R - 1;
int tptr = L;
while (L <= LeftEnd&&R <= RightEnd) {
if (a[L] > a[R]) tmpa[tptr++] = a[R++];
else
tmpa[tptr++] = a[L++];
}
while (L <= LeftEnd)//这里不能写为while(L!=LeftEnd),当L=1,LeftEnd=0的时候会导致泄露
tmpa[tptr++] = a[L++];
while (R <= RightEnd)
tmpa[tptr++] = a[R++];
}
void MSort(int a[], int tmpa[], int L, int RightEnd) {
/*递归:将数组a[]的[L,RightEnd]区间进行归并排序,并且存放到tmpa[]中*/
int center = (L + RightEnd) / 2;
if (L < RightEnd) {
MSort(a, tmpa, L, center);
MSort(a, tmpa, center + 1, RightEnd);
Merge(a, tmpa, L, center + 1, RightEnd);
}
}
void MSort2(int a[], int tmpa[], int N, int length) {
/*将数组a[]中的元素进行归并,然后存放到tmpa[]中,每length个元素段进行归并*/
int i;
for (i = 0; i + 2 * length < N; i =i+length * 2) {
Merge2(a, tmpa, i, i + length, i + 2 * length-1);
}
/*判断剩下的元素是否超过一个length*/
if (i + length < N) {//超过了一个length,将length和残余的合并
Merge2(a, tmpa, i, i + length, N - 1);
}
else
{//余下的元素没有超过一个length,将余下的拷贝到tmpa,注意,余下的子列仍然为有序子列!
for (int j = i; j < N; j++)
tmpa[j] = a[j];
}
}
void MergeSort(int a[], int N) {
int* tmpa = new int[N];
if (tmpa != NULL) {
MSort(a, tmpa, 0, N - 1);
}
delete []tmpa;
}
void MergeSort2(int a[], int N) {
/*非递归*/
int length = 1;
int* tmpa = new int[N];
while (length < N) {
MSort2(a, tmpa, N, length);
length = length * 2;
MSort2(tmpa,a, N, length);//思考:如果length超过了长度,还能够翻过来吗?是可以的,在MSort2函数的最后一种情况中,直接i=0,直接拷贝,此时length>N
length = length * 2;
}
/*for (int i = 0; i < N; i++)
a[i] = tmpa[i];//这一段是不需要的,因为上面的循环会自动的把数组翻过来,因为每一次循环都是从a[]->tmpa[]->a[]*/
delete[]tmpa;
}
int main() {
int N;
cin >> N;
GetData(a, N);
MergeSort2(a, N);
DispArr(a, N);
return 0;
}