8种内部排序算法比较 (C++)
内容
对大量整数或单词排序,分别用内部排序算法-插入排序(1.直接插入排序、2.折半插入排序、3.希尔排序)、交换排序(4.冒泡、5.快速排序)、选择排序(6.直接选择排序、7.堆排序)和归并排序(8.2-路归并排序)具体实现 ,并可计算排序时间,验证时间复杂度。
实验方法
输入实验次数 n n n 和实验数据量 m m m,程序分 n n n 次,每次产生8个相同的长度为 m m m 的随机整数数组,使用上述8种算法进行排序,分别记录运行时长。全部完成后,输出时长列表和平均时长。
源代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#undef OVERFLOW
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define N 8 //函数数量
#define SHOWRESULT 0//显示排序结果
typedef int Keytype;
typedef struct{
Keytype key;
}ElemType;
typedef struct{ //线性顺序表(0号单元不用)
ElemType* r; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量,以sizeof(ElemType)为单位
}SqList;
void InitList(SqList* L,int num,int size);//初始化数据
void Operate(SqList* L,clock_t** time,int num,void (**fun)(SqList&),int times);//排序
void Output(SqList* L,int num,clock_t** time,char** name,int times);
void DestroyList(SqList* L,int num);
int LT(Keytype key1,Keytype key2);//判断小于
void InsertSort(SqList &L);//直接插入排序
void BInsertSort(SqList &L);//折半插入
void ShellSort(SqList &L);//希尔排序
void ShellInsert(SqList &L,int dk);//对一个增量值,完成一轮排序
void Delta(SqList L,int* &delta,int &deltalength);//生成希尔排序的增量数组,采用Hibbard增量序列
void BubbleSort(SqList &L);//冒泡排序
int midindex(SqList L,int low,int high);//中值下标
int Paritition(SqList &L,int low,int high);//对线性表的一部分,确定枢轴和其前后的元素集合
void QSort(SqList &L,int low,int high);//对线性表从low到high的子列采用快排
void QuickSort(SqList &L);//快速排序接口
void SelectSort(SqList &L);//直接选择排序
void HeapSort(SqList &L);//堆排序
void HeapAdjust(SqList &L,int low,int high);//已知以low为堆顶的堆,除堆顶以外均满足堆,调整堆,使之成为大顶堆
void Merge(ElemType* r,ElemType* temp,int n1,int n2,int n3);//将相邻有序的L[n1..n2..n3]归并为有序的T[n1..n3]
void MSort(ElemType* r,ElemType* temp,int low,int high);//将子列归并排序,从r的子列归并到t的子列
void MergeSort(SqList &L);//归并排序接口
/*
对大量整数或单词排序,分别用内部排序算法-插入排序(1.直接插入排序、2.折半插入排序、3.希尔排序)、交换排序(4.冒泡、5.快速排序)、选择排序(6.直接选择排序、7.堆排序)和归并排序(8.2-路归并排序)具体实现 ,并可计算排序时间,验证时间复杂度。
*/
int main()
{
SqList L[N];
clock_t* time[N];
int i,n,m;
void (*fun[N])(SqList&)={InsertSort,BInsertSort,ShellSort,BubbleSort,QuickSort,SelectSort,HeapSort,MergeSort};
char* name[N]={(char*)"直接插入排序",(char*)"折半插入排序",(char*)"希尔排序",(char*)"冒泡排序",(char*)"快速排序",(char*)"直接选择排序",(char*)"堆排序",(char*)"2-路归并排序"};
printf("[不同的排序方法对比]\n");
printf("请分别输入 实验次数 和 实验数据量 : ");
scanf("%d%d",&n,&m);
if(n>0&&m>0){//可运行
for(i=0;i<=N-1;i++) if(!(time[i]=(clock_t*)calloc(n,sizeof(clock_t)))) exit(OVERFLOW);
for(i=0;i<=n-1;i++){
InitList(L,N,m);
Operate(L,time,N,fun,i);
DestroyList(L,N);
}
Output(L,N,time,name,n);
}
system("pause");
}
void InitList(SqList* L,int num,int size)//初始化数据
{
int i,j;
for(i=0;i<=num-1;i++){
L[i].length=size;
if(!(L[i].r=(ElemType*)calloc(L[i].length+1,sizeof(ElemType)))) exit(OVERFLOW);
}
srand((unsigned)time(NULL));
for(i=1;i<=L[0].length;i++) L[0].r[i].key=rand();
for(i=1;i<=num-1;i++){//复制数据
L[i].length=L[0].length;
for(j=1;j<=L[0].length;j++) L[i].r[j]=L[0].r[j];
}
}
void Operate(SqList* L,clock_t** time,int num,void (**fun)(SqList&),int times)//排序
{
clock_t start,end;
int i;
for(i=0;i<=num-1;i++){
start=clock();
fun[i](L[i]);
end=clock();
time[i][times]=end-start;
}
}
void Output(SqList* L,int num,clock_t** time,char** name,int times)
{
int i,j;
double average[num];
for(i=0;i<=num-1;i++){//输出每一种算法的时长列表
printf("%-15s ",name[i]);
#if(SHOWRESULT==OK)
printf("结果: ");
for(j=1;j<=L[i].length;j++) printf("%d ",L[i].r[j].key);
#endif
printf("耗时:\t");
for(j=0;j<=times-1;j++) printf("%d ms\t",time[i][j]);
putchar('\n');
}
printf("\n平均时长\n");
for(i=0;i<=num-1;i++){//计算并输出平均时长列表
average[i]=0;
for(j=0;j<=times-1;j++) average[i]+=time[i][j];
average[i]/=times;
printf("%-15s: %g ms\n",name[i],average[i]);
}
}
void DestroyList(SqList* L,int num)
{
for(num-=1;num>=0;num--){
L[num].length=0;
free(L[num].r);
}
}
int LT(Keytype key1,Keytype key2)//判断序
{
if(key1<key2) return TRUE;
return FALSE;
}
void InsertSort(SqList &L)//直接插入排序
{
int i,j;
for(i=2;i<=L.length;i++){
if(LT(L.r[i].key,L.r[i-1].key)){
L.r[0]=L.r[i];
L.r[i]=L.r[i-1];
for(j=i-2;j>=1&<(L.r[0].key,L.r[j].key);j--){
L.r[j+1]=L.r[j];
}
L.r[j+1]=L.r[0];
}
}
}
void BInsertSort(SqList &L)//折半插入
{
int i,j,mid,low,high;
for(i=2;i<=L.length;i++){
if(LT(L.r[i].key,L.r[i-1].key)){//需要移动
L.r[0]=L.r[i];
for(low=1,high=i-1,mid=(low+high)/2;low<=high;){
if(LT(L.r[0].key,L.r[mid].key)) high=mid-1;
else low=mid+1;
mid=(low+high)/2;
}//插入在low+1位置
for(j=i-1;j>=high+1;j--) L.r[j+1]=L.r[j];
L.r[high+1]=L.r[0];
}
}
}
void ShellInsert(SqList &L,int dk)//对一个增量值,完成一轮排序
{
int i,j;
for(i=dk+1;i<=L.length;i++){
if(LT(L.r[i].key,L.r[i-dk].key)){
L.r[0]=L.r[i];
for(j=i-dk;j>0&<(L.r[0].key,L.r[j].key);j-=dk){
L.r[j+dk]=L.r[j];
}
L.r[j+dk]=L.r[0];
}
}
}
void ShellSort(SqList &L)//希尔排序
{
int i,*delta,deltalength;
Delta(L,delta,deltalength);
for(i=0;i<=deltalength-1;i++) ShellInsert(L,delta[i]);
free(delta);
}
void Delta(SqList L,int* &delta,int &deltalength)//生成希尔排序的增量数组,采用Hibbard增量序列
//采用Hibbard 增量序列,通项d_i=2^i-1,i=1,2,...,[log[2](length)]=deltalength
//此序列倒序填充到delta数组中,i=0,1,2,...,[log[2](length)-1]=deltalength-1
{
int i;
deltalength=log2(L.length);
if(!(delta=(int*)calloc(deltalength,sizeof(int)))) exit(OVERFLOW);
delta[deltalength-1]=1;
for(i=2;deltalength-i>=0;i++) delta[deltalength-i]=2*delta[deltalength-i+1]+1;
}
void BubbleSort(SqList &L)//冒泡排序
{
int i,j,k,change;
for(i=L.length,change=TRUE;i>=2&&change;i--){
change=FALSE;
for(j=1;j<=i-1;j++){
if(LT(L.r[j+1].key,L.r[j].key)){
change=TRUE;
L.r[0]=L.r[j];
L.r[j]=L.r[j+1];
L.r[j+1]=L.r[0];
}
}
}
}
int Paritition(SqList &L,int low,int high)//对线性表的一部分,确定枢轴和其前后的元素集合
{
int i;
i=midindex(L,low,high); //三中值优化
L.r[0]=L.r[i]; //枢轴寄存到0处
if(i!=low) L.r[i]=L.r[low]; //low与i(枢轴)交换
while(low<high){ //起始时,low即为枢轴下标
while(low<high&&!LT(L.r[high].key,L.r[0].key)) high--;
L.r[low]=L.r[high]; //结束时,high为枢轴下标
while(low<high&&!LT(L.r[0].key,L.r[low].key)) low++;
L.r[high]=L.r[low]; //结束时,low为枢轴下标
}
L.r[low]=L.r[0];
return low;
}
int midindex(SqList L,int low,int high)//中值下标
{
if(high<low+2) return low;
int mid=(low+high)/2,o1,o2,o3;
o1=LT(L.r[low].key,L.r[mid].key);
o2=LT(L.r[mid].key,L.r[high].key);
if((o1&&o2)||(!o1&&!o2)) return mid;
o3=LT(L.r[low].key,L.r[high].key);
if((!o1&&o3)||(o1&&!o3)) return low;
return high;
}
void QSort(SqList &L,int low,int high)//对线性表从low到high的子列采用快排
{
int pivotloc;
if(low<high){
pivotloc=Paritition(L,low,high);//确定枢轴位置,移动元素
QSort(L,low,pivotloc-1);
QSort(L,pivotloc+1,high);
}
}
void QuickSort(SqList &L)//快速排序接口
{
QSort(L,1,L.length);
}
void SelectSort(SqList &L)//直接选择排序
{
int i,j,minindex;
for(i=1;i<L.length;i++){//最后一个不需要排
for(j=minindex=i;j<=L.length;j++) if(LT(L.r[j].key,L.r[minindex].key)) minindex=j;//找出从i开始的最小项
if(i!=minindex){
L.r[0]=L.r[i];
L.r[i]=L.r[minindex];
L.r[minindex]=L.r[0];
}
}
}
void HeapSort(SqList &L)//堆排序
{
int i;
for(i=L.length/2;i>0;i--) HeapAdjust(L,i,L.length);//建立大顶堆
for(i=L.length;i>1;i--){//确定第i号元素
L.r[0]=L.r[1];
L.r[1]=L.r[i];
L.r[i]=L.r[0];
HeapAdjust(L,1,i-1);
}
}
void HeapAdjust(SqList &L,int low,int high)//已知以low为堆顶的堆,除堆顶以外均满足堆,调整堆,使之成为大顶堆
{
int i;
L.r[0]=L.r[low];//暂存堆顶元素
for(i=2*low;i<=high;i*=2){
if(i<high&<(L.r[i].key,L.r[i+1].key)) i++;//取兄弟里最大的
if(!LT(L.r[0].key,L.r[i].key)) break;//找到了放置位置
L.r[low]=L.r[i];
low=i; //将更大的上移一层,low更改
}
L.r[low]=L.r[0];//放置原先的堆顶元素
}
void Merge(ElemType* r,ElemType* temp,int n1,int n2,int n3)//将相邻有序的[n1..n2],[n2+1..n3]归并为有序的[n1..n3]
{
int i,j,k;
for(k=i=n1,j=n2+1;i<=n2&&j<=n3;k++){
if(LT(r[i].key,r[j].key)){
temp[k]=r[i];
i++;
}
else{
temp[k]=r[j];
j++;
}
}//k结束时位于被归并的子列后一个位置
if(i<=n2) for(;i<=n2;k++,i++) temp[k]=r[i];
if(j<=n3) for(;j<=n3;j++,k++) temp[k]=r[j];
for(i=n1;i<=n3;i++) r[i]=temp[i];
}
void MSort(ElemType* r,ElemType* temp,int low,int high)//将子列归并排序,从r的子列归并到t的子列
{
int mid=(low+high)/2;
if(low>=high) return;
MSort(r,temp,low,mid);
MSort(r,temp,mid+1,high);
Merge(r,temp,low,mid,high);
}
void MergeSort(SqList &L)//归并排序接口
{
ElemType *temp; //临时数列
if(!(temp=(ElemType*)calloc(L.length+1,sizeof(ElemType)))) exit(OVERFLOW);
MSort(L.r,temp,1,L.length);
free(temp);
}
运行结果