练习7.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
排序算法:
- 插入排序:直接插入排序、折半插入排序、希尔排序
- 交换排序:冒泡排序、快速排序
- 选择排序:简单选择排序、堆排序
- 归并排序
- 基数排序
除了归并排序和堆排序,其他的排序算法的时间复杂度都是O(n*n);
以冒泡排序为例,进行测试。
冒泡排序:
测试点4和测试点8没有过,由此可以判断,时间复杂度为O(n*n)的排序算法不可以通过。
#include<iostream>
using namespace std;
int main()
{
int n,i,t,a[100000];
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n-1;i++)
{
for(int j=0;j<n-1-i;j++)
{
if(a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
for(i=0;i<n;i++)
{
printf("%d",a[i]);
if(i<n-1)
printf(" ");
}
return 0;
}
下面对复杂度为O(nlogN)的函数进行测试
1.使用C++的函数
C++内置的函数的复杂度也是O(nlogN)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n,i,a[100000];
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
for(i=0;i<n;i++)
{
printf("%d",a[i]);
if(i<n-1)
printf(" ");
}
return 0;
}
2.归并排序
#include<iostream>
using namespace std;
void merge(int low,int mid,int high);
int a[100000],b[100000];
int sum=0;
void divid(int low,int high)
{
if(low<high)
{
int mid=(low+high)/2;//找到中间点
divid(low,mid);//左侧递归
divid(mid+1,high);//右侧递归
merge(low,mid,high);//归并
}
}
void merge(int low,int mid,int high)
{
int i=low;
int j=mid+1;
int sign=low;
while((i<=mid)&&(j<=high))//前后两部分均未走完
{
if(a[i]<a[j])
b[sign++]=a[i++];
else
b[sign++]=a[j++];
}
while(i<=mid)//前半段未检测完
b[sign++]=a[i++];
while(j<=high)//后半段未检测完
b[sign++]=a[j++];
for(int k=low;k<=high;k++)//进行赋值
a[k]=b[k];
}
int main()
{
int n,i;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
divid(0,n-1);
for(i=0;i<n;i++)
{
printf("%d",a[i]);
if(i<n-1)
printf(" ");
}
return 0;
}
3.堆排序
#include<stdio.h>
void heap(int a[],int n);
void createheap(int a[],int n);
void AdjustDown(int a[],int k,int len);
void heap(int a[],int n)
{
createheap(a,n);//初始建堆
for(int i=n;i>1;i--)//n-1趟交换和建堆过程
{
int x=a[1];//输出堆顶元素(和堆顶元素进行交换)
a[1]=a[i];
a[i]=x;
AdjustDown(a,1,i-1);//将剩余的i-1和元素整理成堆
}
}
void createheap(int a[],int len)
{
for(int i=len/2;i>0;i--)
AdjustDown(a,i,len);//从后往前第一个有分支的结点处开始调整
}
void AdjustDown(int a[],int k,int len)
{
int t=a[k];
for(int i=2*k;i<=len;i*=2)//沿着较大的子结点向下筛选
{
if(i<len&&a[i]<a[i+1])
i++;//取较大子结点的下标
if(t>=a[i])
break;//筛选结束
else{
a[k]=a[i];//将a[i]调整到双亲结点上
k=i;//修改k值,以便继续向下筛选
}
}
a[k]=t;
}
int main()
{
int n,i,t,a[100000];
scanf("%d",&n);
a[0]=0;//堆排序的0位置用来进行比较
for(i=1;i<=n;i++)//从第一个位置进行读入
scanf("%d",&a[i]);
heap(a,n);
for(i=1;i<=n;i++)
{
printf("%d",a[i]);
if(i<n)
printf(" ");
}
return 0;
}