设计程序,利用随机函数产生20000个随机整数(1~1000000),完成下面功能:
(1)对这些数分别进行直接插入排序、折半插入排序、希尔排序、起泡排序、快速排序、简单选择排序、堆排序、2-路归并排序,并把排序结果保存到文件中。
(2)分析上述排序算法的性能(以运行程序所花费的时间为准进行对比),找出较快的排序方法。
(3)若排序的整数增加到100000个、100000000个,以上排序结果有什么变化,请分析并验证。
#include<iostream>
#include<cstdlib>
#include<ctime>
#define MAXSIZE 20000 //顺序表最大长度
using namespace std ;
typedef struct{
int key; //关键字项,关键字类型为整形
char *otherinfo; //其它数据项
}RedType; //记录类型
typedef struct{
RedType r[MAXSIZE+1]; //0号单元闲置
int length; //顺序表长度
}SqList; //顺序表类型
//直接插入排序
void InsertSort(SqList &L)
{
int j ;
for(int i=2;i<=L.length;i++)
{
if(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;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)
{
for(int i=2;i<L.length;i++)
{
L.r[0] = L.r[i] ;
int low = 1 ;
int high = i-1 ;
while(low <=high)
{
int m=(low+high)/2 ;
if(L.r[0].key<L.r[m].key)
high = m-1 ;
else
low = m+1 ;
}
for(int j=i-1;j>high+1;--j)
L.r[j+1]=L.r[j] ;
L.r[high+1] = L.r[0] ;
}
}
//希尔排序 ShellInsert() ShellSort()
//对顺序表L中的记录进行一趟增量为dk的希尔排序
void ShellInsert(SqList &L,int dk)
{
int j ;
for(int i=dk+1;i<=L.length;i++)
if(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] ;
}
}
//对顺序表L中的记录按增量序列(存储在数组dt中)进行t趟希尔排序
void ShellSort(SqList &L,int dt[],int t)
{
for(int k=0;k<t;++k)
ShellInsert(L,dt[k]) ;
}
//冒泡排序
void BubbleSort(SqList &L)
{//对顺序表L进行冒泡排序
int m = L.length - 1 ;
int flag = 1 ; //flag 用来标记某一烫排序是否发生交换
while((m>0)&&(flag==1))
{
flag = 0 ; //flag 置为 0 ,如果本趟排序没有发生交换,则不会执行下一趟排序
for(int j=1;j<=m;j++)
if(L.r[j].key>L.r[j+1].key)
{
flag = 1 ; //flag置为 1 表示本趟排序发生了交换
RedType t = L.r[j];
L.r[j] = L.r[j+1] ;
L.r[j+1] = t ; //交换前后两个记录
}
--m ;
}
}
//快速排序 Partition() QSort() QuickSort()
//对顺序表L中的子表L.r[low...high]进行一次划分,并返回枢轴位置
int Partition(SqList &L,int low,int high)
{
L.r[0] = L.r[low] ;
int pivotkey = L.r[low].key ;
while(low<high)
{
while(low<high&&L.r[high].key>=pivotkey)
--high ;
L.r[low] = L.r[high] ;
while(low<high&&L.r[low].key<=pivotkey)
++low ;
L.r[high] = L.r[low] ;
}
L.r[low] = L.r[0] ;
return low ;
}
//对顺序表L中的子序列L.r[low...high]进行快速排序
void QSort(SqList &L,int low,int high)
{
if(low<high)
{
int pivotloc = Partition(L,low,high) ;
QSort(L,low,pivotloc-1) ;
QSort(L,pivotloc+1,high) ;
}
}
//对顺序表L中的记录进行快速排序
void QuickSort(SqList &L)
{
QSort(L,1,L.length) ;
}
//简单选择排序
void SelectSort(SqList &L)
{//对顺序表L做简单选择排序
for(int i=1;i<L.length;i++)
{//在 L.r[i....L.length]中选择关键字最小的记录
int k = i ;
for(int j=i+1;j<L.length;j++)
if(L.r[j].key<L.r[k].key)
k = j ; // k 指向此趟排序中关键字最小的记录
if(k!=i)
{
RedType t = L.r[i] ;
L.r[i] = L.r[k] ;
L.r[k] = t ; //交换 r[i]与r[k]
}
}
}
//堆排序 HeapAdjust() CreatHeap() HeapSort()
//筛选法调整堆
void HeapAdjust(SqList &L,int s,int m)
{//假设 r[s+1..m]已经是堆,将r[s.m] 调整为以 r[s] 为根的大根堆
RedType rc = L.r[s] ;
for(int j=2*s;j<=m;j*=2) //沿key较大的孩子结点向下筛选
{
if(j<m&&L.r[j].key<L.r[j+1].key)
++j ; // j 为 key 较大的记录的下标
if(rc.key>=L.r[j].key) // rc 应插入在位置 s 上
break ;
L.r[s] = L.r[j] ;
s = j ;
}
L.r[s] = rc ;
}
//初建堆
void CreatHeap(SqList &L)
{//把无序序列 L.r[1...n] 建成大根堆
int n = L.length ;
for(int i=n/2;i>0;i--) //反复调用HeapAdjust
HeapAdjust(L,i,n) ;
}
//堆排序算法实现
void HeapSort(SqList &L)
{
CreatHeap(L) ;//把无序序列 L.r[1...L.length] 建成大根堆
for(int i=L.length;i>1;i--)
{
RedType x = L.r[1] ; //将堆记录和当前未经排序L.r[1...i]中最后一个记录互换
L.r[1] = L.r[i] ;
L.r[i] = x ;
HeapAdjust(L,1,i-1) ;//将L.r[1...i-1] 重新调整为大根堆
}
}
// 2-路归并排序
//相邻两个有序子序列的归并
void Merge(RedType R[],RedType T[],int low,int mid,int high)
{//将有序表R[low...mid]和R[mid+1...hight] 归并为有序列表T[low...hight]
int i = low ;
int j = mid + 1 ;
int k = low ;
while(i<=mid&&j<=high) // 将 R 中记录由小到大并入 T 中
{
if(R[i].key<=R[j].key)
T[k++] = R[i++] ;
else
T[k++] = R[j++] ;
}
while(i<=mid)
T[k++] = R[i++] ; //将剩余的 R[i..mid] 复制到 T 中
while(j<=high)
T[k++] = R[j++] ; //将剩余的 R[j..high] 复制到 T 中
}
//分
void MSort(RedType R[],RedType T[],int low,int high)
{ //R[low..high] 归并排序后放入 T[low..high]中
if(low == high)
T[low] = R[low] ;
else
{
RedType S[MAXSIZE+1];
int mid = (low+high) / 2 ;
MSort(R,S,low,mid) ;
MSort(R,S,mid+1,high);
Merge(S,T,low,mid,high) ;
}
}
//递归调用排序
void MergeSort(SqList &L)
{
MSort(L.r,L.r,1,L.length) ;
}
//创建顺序表:向顺序表L中添加10个记录,记录的关键字为1-100范围内的随机整数
void CreateList(SqList &L)
{
int i;
srand(time(0));
for(i=1;i<20000;i++)
{
L.r[i].key =rand()%1000000+1;
}
L.length =20000;
}
//菜单
void showmenu()
{
printf("-------------操作选项---------------\n") ;
printf("------------------------------------\n") ;
printf(" 1、直接插入排序\n") ;
printf(" 2、折半插入排序\n") ;
printf(" 3、希尔排序\n") ;
printf(" 4、冒泡排序\n") ;
printf(" 5、快速排序\n") ;
printf(" 6、简单选择排序\n") ;
printf(" 7、堆排序\n") ;
printf(" 8、归并排序\n") ;
printf("------------------------------------\n") ;
}
int main()
{
SqList L;
CreateList(L); //创建顺序表L,生成随机数
clock_t start, finish ;//每个函数开始和结束的时间
double shijian = 0.0 ; //函数 结束的时间-开始的时间=排序总用时
int n,dt[3]={5,3,1}; //dt中存放的是希尔排序时使用的三个增量
showmenu() ;
printf("\n") ;
printf("测试数据量:1000\n") ;
printf("\n") ;
//将生成的随机数读入到 data.doc 文件中
FILE * fpWrite = fopen("C:\\Users\\LZY\\Desktop\\data.doc","w") ;
for(int i=1;i<=L.length;i++)
fprintf(fpWrite,"%-8d ",L.r[i].key) ;
if(fpWrite!=NULL)
printf("初始数据读入文件成功\n") ;
fclose(fpWrite) ; //关闭文件
cin>>n; //输出选择的排序方法序号
while(n!=0) //循环显示菜单,按0结束程序
{
switch(n) //根据选择的序号调用不同的排序方法
{
case 1:
start = clock() ;
InsertSort(L); //直接插入排序
finish = clock() ;
shijian = double(finish - start) ;
printf("直接插入排序耗时:%lf \n",shijian) ;
break;
case 2:
start = clock() ;
BInsertSort(L); //折半插入排序
finish = clock() ;
shijian = double(finish - start) ;
printf("折半插入排序耗时:%lf \n",shijian) ;
break;
case 3:
start = clock() ;
ShellSort(L,dt,3); //希尔排序,(3趟)
finish = clock() ;
shijian = double(finish - start) ;
printf("希尔排序耗时:%lf \n",shijian) ;
break;
case 4:
start = clock() ;
BubbleSort(L); //冒泡排序
finish = clock() ;
shijian = double(finish - start) ;
printf("冒泡排序耗时:%lf \n",shijian) ;
break ;
case 5:
start = clock() ;
QuickSort(L); //快速排序
finish = clock() ;
shijian = double(finish - start) ;
printf("快速排序耗时:%lf \n",shijian) ;
break;
case 6:
start = clock() ;
SelectSort(L); //简单选择排序
finish = clock() ;
shijian = double(finish - start) ;
printf("简单选择排序耗时:%lf \n",shijian) ;
break;
case 7:
start = clock() ;
HeapSort(L); //堆排序
finish = clock() ;
shijian = double(finish - start) ;
printf("堆排序耗时:%lf \n",shijian) ;
break;
case 8:
start = clock() ;
MergeSort(L); //归并排序
finish = clock() ;
shijian = double(finish - start) ;
printf("归并排序耗时:%lf \n",shijian) ;
break;
default:
cout<<"序号选择错误,请重新选择!"<<endl;
break;
}
//将排序后的数据读入到 data1.doc 文件中
FILE * fpWrite = fopen("C:\\Users\\LZY\\Desktop\\data1.doc","w") ;
for(int i=1;i<=L.length;i++)
fprintf(fpWrite,"%-8d ",L.r[i].key) ;
if(fpWrite!=NULL)
printf("排序后数据读入文件成功\n") ;
fclose(fpWrite) ; //关闭文件
CreateList(L); //每次排序后,重置L中的10个记录
cin>>n;
}
return 0 ;
}