第15周项目2

来源:互联网 发布:ubuntu版的qq 编辑:程序博客网 时间:2024/06/07 05:03
  1. /* 
  2. 烟台大学计算机与控制工程学院 
  3.  
  4. 姓名:潘亚楠
  5.  
  6. 日期:2017.12.20
  7.  
  8. 文件名称:ycds2017 
  9.  
  10. 问题描述:设计一个函数,产生一个至少5万条记录的数据集合。 
  11. 在同一数据集上,用直接插入排序、冒泡排序、快速排序、直接选择排序、堆排序、归并排序、基数排序等算法进行排序, 
  12. 记录所需要的时间,经过对比,得到对复杂度不同的各种算法在运行时间方面的感性认识。 
  13.  
  14.  
  15. 输入:无 
  16.  
  17.  
  18. 输出:各排序算法的时间 
  19.  
  20. 分文件 
  21.  
  22.  
  23. */  
  24.   
  25. //sort.h:  
  26.   
  27. #define MaxSize 50000      //最多的数据,取5万,只测试快速算法,可以往大调整  
  28.   
  29. //下面的符号常量和结构体针对基数排序  
  30. #define Radix 10           //基数的取值  
  31. #define Digits 10          //关键字位数  
  32.   
  33. typedef int KeyType;    //定义关键字类型  
  34. typedef char InfoType[10];  
  35. typedef struct          //记录类型  
  36. {  
  37.     KeyType key;        //关键字项  
  38.     InfoType data;      //其他数据项,类型为InfoType  
  39. } RecType;              //排序的记录类型定义  
  40.   
  41. typedef struct node  
  42. {  
  43.     KeyType data;      //记录的关键字,同算法讲解中有差别  
  44.     struct node *next;  
  45. } RadixRecType;  
  46.   
  47. void InsertSort(RecType R[],int n); //直接插入排序  
  48. void ShellSort(RecType R[],int n);  //希尔排序算法  
  49. void BubbleSort(RecType R[],int n); //冒泡排序  
  50. void QuickSort(RecType R[],int n);  //快速排序  
  51. void SelectSort(RecType R[],int n);  //直接选择排序  
  52. void HeapSort(RecType R[],int n);  //堆排序  
  53. void MergeSort(RecType R[],int n); //归并排序  
  54.   
  55. //下面函数支持基数排序  
  56. void CreateLink(RadixRecType *&p,RecType R[],int n);   //创建基数排序用的链表  
  57. void DestoryLink(RadixRecType *&p); //释放基数排序用的链表  
  58. void RadixSort(RadixRecType *&p); //基数排序  
  59.   
  60.   
  61. //sort.cpp:  
  62.   
  63. #include "sort.h"  
  64. #include <malloc.h>  
  65.   
  66. //1. 对R[0..n-1]按递增有序进行直接插入排序  
  67. void InsertSort(RecType R[],int n)  
  68. {  
  69.     int i,j;  
  70.     RecType tmp;  
  71.     for (i=1; i<n; i++)  
  72.     {  
  73.         tmp=R[i];  
  74.         j=i-1;            //从右向左在有序区R[0..i-1]中找R[i]的插入位置  
  75.         while (j>=0 && tmp.key<R[j].key)  
  76.         {  
  77.             R[j+1]=R[j]; //将关键字大于R[i].key的记录后移  
  78.             j--;  
  79.         }  
  80.         R[j+1]=tmp;      //在j+1处插入R[i]  
  81.     }  
  82. }  
  83.   
  84.   
  85. //2. 希尔排序算法  
  86. void ShellSort(RecType R[],int n)  
  87. {  
  88.     int i,j,gap;  
  89.     RecType tmp;  
  90.     gap=n/2;                //增量置初值  
  91.     while (gap>0)  
  92.     {  
  93.         for (i=gap; i<n; i++) //对所有相隔gap位置的所有元素组进行排序  
  94.         {  
  95.             tmp=R[i];  
  96.             j=i-gap;  
  97.             while (j>=0 && tmp.key<R[j].key)//对相隔gap位置的元素组进行排序  
  98.             {  
  99.                 R[j+gap]=R[j];  
  100.                 j=j-gap;  
  101.             }  
  102.             R[j+gap]=tmp;  
  103.             j=j-gap;  
  104.         }  
  105.         gap=gap/2;  //减小增量  
  106.     }  
  107. }  
  108.   
  109. //3. 冒泡排序  
  110. void BubbleSort(RecType R[],int n)  
  111. {  
  112.     int i,j,exchange;  
  113.     RecType tmp;  
  114.     for (i=0; i<n-1; i++)  
  115.     {  
  116.         exchange=0;  
  117.         for (j=n-1; j>i; j--)   //比较,找出最小关键字的记录  
  118.             if (R[j].key<R[j-1].key)  
  119.             {  
  120.                 tmp=R[j];  //R[j]与R[j-1]进行交换,将最小关键字记录前移  
  121.                 R[j]=R[j-1];  
  122.                 R[j-1]=tmp;  
  123.                 exchange=1;  
  124.             }  
  125.         if (exchange==0)    //没有交换,即结束算法  
  126.             return;  
  127.     }  
  128. }  
  129.   
  130. //4. 对R[s]至R[t]的元素进行快速排序  
  131. void QuickSortR(RecType R[],int s,int t)  
  132. {  
  133.     int i=s,j=t;  
  134.     RecType tmp;  
  135.     if (s<t)                //区间内至少存在两个元素的情况  
  136.     {  
  137.         tmp=R[s];           //用区间的第1个记录作为基准  
  138.         while (i!=j)        //从区间两端交替向中间扫描,直至i=j为止  
  139.         {  
  140.             while (j>i && R[j].key>=tmp.key)  
  141.                 j--;        //从右向左扫描,找第1个小于tmp.key的R[j]  
  142.             R[i]=R[j];      //找到这样的R[j],R[i]"R[j]交换  
  143.             while (i<j && R[i].key<=tmp.key)  
  144.                 i++;        //从左向右扫描,找第1个大于tmp.key的记录R[i]  
  145.             R[j]=R[i];      //找到这样的R[i],R[i]"R[j]交换  
  146.         }  
  147.         R[i]=tmp;  
  148.         QuickSortR(R,s,i-1);     //对左区间递归排序  
  149.         QuickSortR(R,i+1,t);     //对右区间递归排序  
  150.     }  
  151. }  
  152.   
  153. //4. 快速排序辅助函数,对外同其他算法统一接口,内部调用递归的快速排序  
  154. void QuickSort(RecType R[],int n)  
  155. {  
  156.     QuickSortR(R, 0, n-1);  
  157. }  
  158.   
  159. //5. 直接选择排序  
  160. void SelectSort(RecType R[],int n)  
  161. {  
  162.     int i,j,k;  
  163.     RecType temp;  
  164.     for (i=0; i<n-1; i++)           //做第i趟排序  
  165.     {  
  166.         k=i;  
  167.         for (j=i+1; j<n; j++)   //在当前无序区R[i..n-1]中选key最小的R[k]  
  168.             if (R[j].key<R[k].key)  
  169.                 k=j;            //k记下目前找到的最小关键字所在的位置  
  170.         if (k!=i)               //交换R[i]和R[k]  
  171.         {  
  172.             temp=R[i];  
  173.             R[i]=R[k];  
  174.             R[k]=temp;  
  175.         }  
  176.     }  
  177. }  
  178.   
  179. //6. 堆排序辅助之——调整堆  
  180. void sift(RecType R[],int low,int high)  
  181. {  
  182.     int i=low,j=2*i;                        //R[j]是R[i]的左孩子  
  183.     RecType temp=R[i];  
  184.     while (j<=high)  
  185.     {  
  186.         if (j<high && R[j].key<R[j+1].key)  //若右孩子较大,把j指向右孩子  
  187.             j++;                                //变为2i+1  
  188.         if (temp.key<R[j].key)  
  189.         {  
  190.             R[i]=R[j];                          //将R[j]调整到双亲结点位置上  
  191.             i=j;                                //修改i和j值,以便继续向下筛选  
  192.             j=2*i;  
  193.         }  
  194.         else break;                             //筛选结束  
  195.     }  
  196.     R[i]=temp;                                  //被筛选结点的值放入最终位置  
  197. }  
  198.   
  199. //6. 堆排序  
  200. void HeapSort(RecType R[],int n)  
  201. {  
  202.     int i;  
  203.     RecType temp;  
  204.     for (i=n/2; i>=1; i--) //循环建立初始堆  
  205.         sift(R,i,n);  
  206.     for (i=n; i>=2; i--) //进行n-1次循环,完成推排序  
  207.     {  
  208.         temp=R[1];       //将第一个元素同当前区间内R[1]对换  
  209.         R[1]=R[i];  
  210.         R[i]=temp;  
  211.         sift(R,1,i-1);   //筛选R[1]结点,得到i-1个结点的堆  
  212.     }  
  213. }  
  214.   
  215. //7.归并排序辅助1——合并有序表  
  216. void Merge(RecType R[],int low,int mid,int high)  
  217. {  
  218.     RecType *R1;  
  219.     int i=low,j=mid+1,k=0; //k是R1的下标,i、j分别为第1、2段的下标  
  220.     R1=(RecType *)malloc((high-low+1)*sizeof(RecType));  //动态分配空间  
  221.     while (i<=mid && j<=high)       //在第1段和第2段均未扫描完时循环  
  222.         if (R[i].key<=R[j].key)     //将第1段中的记录放入R1中  
  223.         {  
  224.             R1[k]=R[i];  
  225.             i++;  
  226.             k++;  
  227.         }  
  228.         else                            //将第2段中的记录放入R1中  
  229.         {  
  230.             R1[k]=R[j];  
  231.             j++;  
  232.             k++;  
  233.         }  
  234.     while (i<=mid)                      //将第1段余下部分复制到R1  
  235.     {  
  236.         R1[k]=R[i];  
  237.         i++;  
  238.         k++;  
  239.     }  
  240.     while (j<=high)                 //将第2段余下部分复制到R1  
  241.     {  
  242.         R1[k]=R[j];  
  243.         j++;  
  244.         k++;  
  245.     }  
  246.     for (k=0,i=low; i<=high; k++,i++) //将R1复制回R中  
  247.         R[i]=R1[k];  
  248. }  
  249.   
  250. //7. 归并排序辅助2——一趟归并  
  251. void MergePass(RecType R[],int length,int n)    //对整个数序进行一趟归并  
  252. {  
  253.     int i;  
  254.     for (i=0; i+2*length-1<n; i=i+2*length)     //归并length长的两相邻子表  
  255.         Merge(R,i,i+length-1,i+2*length-1);  
  256.     if (i+length-1<n)                       //余下两个子表,后者长度小于length  
  257.         Merge(R,i,i+length-1,n-1);          //归并这两个子表  
  258. }  
  259.   
  260. //7. 归并排序  
  261. void MergeSort(RecType R[],int n)           //自底向上的二路归并算法  
  262. {  
  263.     int length;  
  264.     for (length=1; length<n; length=2*length) //进行log2n趟归并  
  265.         MergePass(R,length,n);  
  266. }  
  267.   
  268. //以下基数排序,为了统一测试有改造  
  269. //8. 基数排序的辅助函数,创建基数排序用的链表  
  270. void CreateLink(RadixRecType *&p,RecType R[],int n)   //采用后插法产生链表  
  271. {  
  272.     int i;  
  273.     RadixRecType *s,*t;  
  274.     for (i=0; i<n; i++)  
  275.     {  
  276.         s=(RadixRecType *)malloc(sizeof(RadixRecType));  
  277.         s->data = R[i].key;  
  278.         if (i==0)  
  279.         {  
  280.             p=s;  
  281.             t=s;  
  282.         }  
  283.         else  
  284.         {  
  285.             t->next=s;  
  286.             t=s;  
  287.         }  
  288.     }  
  289.     t->next=NULL;  
  290. }  
  291.   
  292. //8. 基数排序的辅助函数,释放基数排序用的链表  
  293. void DestoryLink(RadixRecType *&p)  
  294. {  
  295.     RadixRecType *q;  
  296.     while(p!=NULL)  
  297.     {  
  298.         q=p->next;  
  299.         free(p);  
  300.         p=q;  
  301.     }  
  302.     return;  
  303. }  
  304.   
  305. //8. 实现基数排序:*p为待排序序列链表指针,基数R和关键字位数D已经作为符号常量定义好  
  306. void RadixSort(RadixRecType *&p)  
  307. {  
  308.     RadixRecType *head[Radix],*tail[Radix],*t; //定义各链队的首尾指针  
  309.     int i,j,k;  
  310.     unsigned int d1, d2=1;   //用于分离出第i位数字,见下面的注释  
  311.     for (i=1; i<=Digits; i++)                  //从低位到高位循环  
  312.     {  
  313.         //分离出倒数第i位数字,先通过对d1=10^i取余,得到其后i位,再通过整除d2=10^(i-1)得到第i位  
  314.         //例如,分离出倒数第1位,即个位数,先对d1=10取余,再整除d2=1  
  315.         //再例如,分离出倒数第2位,即十位数,先对d1=100取余,再整除d2=10  
  316.         //循环之前,d2已经初始化为1,在这一层循环末增加10倍  
  317.         //下面根据d2,得到d1的值  
  318.         d1=d2*10;  
  319.         for (j=0; j<Radix; j++)                 //初始化各链队首、尾指针  
  320.             head[j]=tail[j]=NULL;  
  321.         while (p!=NULL)                 //对于原链表中每个结点循环  
  322.         {  
  323.             k=(p->data%d1)/d2;           //分离出第i位数字k  
  324.             if (head[k]==NULL)          //进行分配  
  325.             {  
  326.                 head[k]=p;  
  327.                 tail[k]=p;  
  328.             }  
  329.             else  
  330.             {  
  331.                 tail[k]->next=p;  
  332.                 tail[k]=p;  
  333.             }  
  334.             p=p->next;                  //取下一个待排序的元素  
  335.         }  
  336.         p=NULL;                         //重新用p来收集所有结点  
  337.         for (j=0; j<Radix; j++)             //对于每一个链队循环  
  338.             if (head[j]!=NULL)          //进行收集  
  339.             {  
  340.                 if (p==NULL)  
  341.                 {  
  342.                     p=head[j];  
  343.                     t=tail[j];  
  344.                 }  
  345.                 else  
  346.                 {  
  347.                     t->next=head[j];  
  348.                     t=tail[j];  
  349.                 }  
  350.             }  
  351.         t->next=NULL;                   //最后一个结点的next域置NULL  
  352.         //下面更新用于分离出第i位数字的d2  
  353.         d2*=10;  
  354.     }  
  355. }  
  356.   
  357.   
  358. //main.cpp:  
  359.   
  360. #include <stdio.h>  
  361. #include <malloc.h>  
  362. #include <stdlib.h>  
  363. #include <time.h>  
  364. #include "sort.h"  
  365.   
  366. void GetLargeData(RecType *&R, int n)  
  367. {  
  368.     srand(time(0));  
  369.     R=(RecType*)malloc(sizeof(RecType)*n);  
  370.     for(int i=0; i<n; i++)  
  371.         R[i].key= rand();  //产生0~RAND_MAX间的数  
  372.     printf("生成了%d条记录\n", n);  
  373. }  
  374.   
  375. //调用某一排序算法完成排序,返回排序用时  
  376. long Sort(RecType *&R, int n, void f(RecType*, int))  
  377. {  
  378.     int i;  
  379.     long beginTime, endTime;  
  380.     RecType *R1=(RecType*)malloc(sizeof(RecType)*n);  
  381.     for (i=0;i<n;i++)  
  382.         R1[i]=R[i];  
  383.     beginTime = time(0);  
  384.     f(R1,n);  
  385.     endTime = time(0);  
  386.     free(R1);  
  387.     return endTime-beginTime;  
  388. }  
  389.   
  390. //调用基数排序算法完成排序,返回排序用时  
  391. long Sort1(RecType *&R, int n)  
  392. {  
  393.     long beginTime, endTime;  
  394.     RadixRecType *p;  
  395.     CreateLink(p,R,n);  
  396.     beginTime = time(0);  
  397.     RadixSort(p);  
  398.     endTime = time(0);  
  399.     DestoryLink(p);  
  400.     return endTime-beginTime;  
  401. }  
  402.   
  403. int main()  
  404. {  
  405.     RecType *R;  
  406.     int n = MaxSize;   //测试中, MaxSize取50W  
  407.     GetLargeData(R, n);  
  408.     printf("各种排序花费时间:\n");  
  409.     printf("  直接插入排序:%ld\n", Sort(R, n, InsertSort));  
  410.     printf("  希尔排序:%ld\n", Sort(R, n, ShellSort));  
  411.     printf("  冒泡排序:%ld\n", Sort(R, n, BubbleSort));  
  412.     printf("  快速排序:%ld\n", Sort(R, n, QuickSort));  
  413.     printf("  直接选择排序:%ld\n", Sort(R, n, SelectSort));  
  414.     printf("  堆排序:%ld\n", Sort(R, n, HeapSort));  
  415.     printf("  归并排序:%ld\n", Sort(R, n, MergeSort));  
  416.     printf("  基数排序:%ld\n", Sort1(R, n));  
  417.     free(R);  
  418.     return 0;  
  419. }  

运行结果:

原创粉丝点击