目 录
3.1 合理调用rands(),rand()生成数据(2分)... - 3 -
3.2 合理保障输入各个排序算法的数据一致性(2分)... - 3 -
3.3 获取、计算、输出各个排序算法的运行时间(2分)... - 3 -
2.3.1数量级10000上的性能比较(1分)... - 5 -
2.3.2数量级100000上的性能比较(1分)... - 5 -
2.3.3数量级1000000上的性能比较(1分)... - 5 -
第1章 实验基本信息
1.1 实验目的
-
- 利用Makefile管理编译过程
- 熟练掌握典型排序算法
- 熟练掌握Linux下程序的调试
- 理解算法对性能的影响
1.2 实验环境与工具
1.2.1 硬件环境
-
- 硬件平台:Intel X86-64、ARM v8鲲鹏920处理器、香橙派/树莓派
1.2.2 软件环境
-
- Ubuntu 18.04 LTS 64以上
(或Windows/MacOS + 虚拟机VirtualBox/Vmware );
- Ubuntu 18.04 LTS 64以上
1.2.3 开发工具
-
- gcc、g++;vi/vim/gedit
第2章 数据生成和性能测试
测试程序代码如下,已给出
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "sort.h"
#define Debug
//you must specify a int to indicate the data type to be sorted
int dataType = STUDENT;
//utilites to be used in main
//provide compare function
int cmp(ElemType * a, ElemType *b);
//to generate random data
void generateData(ElemType * A, int num);
void randName(char * name);
void randID(char * id);
//to output small array in debug
void output(ElemType A[],int n, char * info);
int main(int argc, char ** argv)
{
size_t t1, t2;
int size;
ElemType *orig, *toSort;
int (*cmpare)(ElemType * a, ElemType *b);
cmpare = &cmp;
if(argc<2)
return 1;
sscanf(argv[1], "%d", &size);
if(size<=0)
return 0;
orig = (ElemType*) malloc(sizeof(ElemType)*size);
toSort = (ElemType*) malloc(sizeof(ElemType)*size);
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(ElemType));
#ifdef Debug
output(toSort, size,"SelectSort: before");
#endif
t1 = clock();
SelectSort(toSort, size, cmpare);
t2 = clock();
#ifdef Debug
output(toSort, size, "SelectSort: after");
#endif
printf("SelectSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
return 1;
}
int cmp(ElemType * a, ElemType *b)
{
if(dataType == INT)
{
if(*((int*)a) == *((int*)b))
return 0;
else if (*((int*)a)> *((int*)b))
return 1;
else
return -1;
}
else if(dataType == FLOAT)
{
if(*((float*)a) == *((float*)b))
return 0;
else if (*((float*)a)> *((float*)b))
return 1;
else
return -1;
}
else if(dataType == DOUBLE)
{
if(*((double*)a) == *((double*)b))
return 0;
else if (*((double*)a)> *((double*)b))
return 1;
else
return -1;
}
else
{
STU * pa = (STU *)a;
STU * pb = (STU *)b;
if(pa->total == pb->total)
return 0;
else if (pa->total > pb->total)
return 1;
else
return -1;
}
}
void generateData(ElemType * A, int num)
{
if(dataType == INT)
{
for(int i=0; i<num; i++)
{
*((int*)(A+i)) = rand()%(10*num);
}
}
else if(dataType == FLOAT)
{
for(int i=0; i<num; i++)
{
*((float*)(A+i)) = rand()%(10*num);
}
}
else if(dataType == DOUBLE)
{
for(int i=0; i<num; i++)
{
*((double*)(A+i)) = rand()%(10*num);
}
}
else
{
for(int i=0; i<num; i++)
{
randID(((STU*)(A+i))->id);
randName( ((STU*)(A+i))->name);
((STU*)(A+i))->total = 0;
for(int j=0; j<5; j++)
{
((STU*)(A+i))->score[j] = (rand()%10000)/((double) 100);
((STU*)(A+i))->total += ((STU*)(A+i))->score[j];
}
}
}
}
void randName(char * name)
{
char ALPHA[26]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char alpha[26]="abcdefghijklmnopqrstuvwxyz";
int len = 1+ rand()%18;
name[0] = ALPHA[rand()%26];
for(int i=1; i<len; i++)
{
name[i] = alpha[rand()%26];
}
name[len] = '\0';
}
void randID(char * id)
{
char buf[20] = "2021031";
char buf1[3];
char buf2[5];
int classNo = rand()%100;
int stuNo = rand()%10000;
sprintf(buf1, "%02d", classNo);
buf1[2] = '\0';
sprintf(buf2, "%04d", stuNo);
buf2[4] = '\0';
strcat(buf, buf1);
strcat(buf, buf2);
strcpy(id, buf);
}
void output(ElemType A[],int n, char * info)
{
printf("%s\n", info);
switch(dataType)
{
case INT:
for(int i=0; i<n; i++)
{
printf("%d ", *((int*)(A+i)));
}
printf("\n");
break;
case FLOAT:
for(int i=0; i<n; i++)
{
printf("%f ", *((float*)(A+i)));
}
printf("\n");
break;
case DOUBLE:
for(int i=0; i<n; i++)
{
printf("%f ", *((double*)(A+i)));
}
printf("\n");
break;
case STUDENT:
for(int i=0; i<n; i++)
{
printf("%s %-20s ", ((STU*)(A+i))->id, ((STU*)(A+i))->name);
for(int j=0; j<5; j++)
{
printf("%f ", ((STU*)(A+i))->score[j]);
}
printf("%f \n", ((STU*)(A+i))->total);
}
break;
default:
break;
}
}
第3章 排序算法
2.1 平方级排序算法
2.1.1冒泡排序算法
#include <stdio.h>
#include <stdlib.h>
#include "sort.h"
//
//
//
void bubble_sort(int n,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n-i-1;j++)
{
if(cmp(A+j,A+j+1)>0)//compare the next data
swap(A,j,j+1);//if position wrong then swap
}
}
}
算法思想:遍历数组,比较相邻俩人大小,每当遇到前>后则交换,则第一轮确定最后一个数为最大数,第二轮确定倒数第二个数为最大数……
2.1.2选择排序算法
#include <stdio.h>
#include <stdlib.h>
#include "sort.h"
//input:the scale of array n,the array which need sort A,two pointers point to the array
//output:null
//function:manage selcect sort
void selection_sort(int n,elem_type *A,int (*cmp)(elem_type *,elem_type *))
{
for(int i = 0; i<n;i++)
{
int j=i;//ues j to recode the min data
for(int k=i+1;k<n;k++)
{
if(cmp(A+j,A+k)>0)//A[j]>A[k]
j=k;//if smaller,updata j
}
swap(A,i,j);
}
}
算法思想:遍历数组,选定第i个元素,向后搜索比他小的数并记录,最后交换
2.1.2插入排序算法
#include <stdio.h>
#include <stdlib.h>
#include "sort.h"
//
//
//
void insert_sort(int n,elem_type *A,int (*cmp)(elem_type*,elem_type*))
{
for(int i=0;i<n;i++)
{
elem_type temp = *(A+i);//catch the cunrent number
elem_type *tp = &temp;
int k=i-1;
while(cmp(A+k,tp)>0&&k>=0)//A[k]>A[i]
{
A[k+1]=A[k];//A[k] move to tail next to next
k--;
}
A[k+1]=temp;//get the position of i insert
}
}
思想:遍历数组,每次抓牌,确定第一个比该数大的数,得到插入位置k,把k后每个元素后移一位,最后把手上的牌插进去
2.2 nlogn排序算法
2.2.1归并排序算法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sort.h"
void merge_sort(int i,int j,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
if(j<=i)return;
int k=(i+j)/2;
merge_sort(i,k,A,cmp);//caculate the left half of array
merge_sort(k+1,j,A,cmp);//caculate the right half of array
int l=i;//the left array pointer
int h=k+1;//the right array pointer
int t=0;//the B pointer
elem_type *B=(elem_type *)(malloc((j-i+1)*sizeof(elem_type)));//get the space of B
if(B==NULL)//check the return value of malloc to avoid error
{printf("memory get wrong!\n");
return;}//check the error
while(l<=k&&h<=j)// merge the left and the right array
{
if(cmp(A+h,A+l)>0)//A[h]>A[l]
{
B[t]=A[l];//get A[l] to B
l++;
t++;
}
else
{
B[t]=A[h];//get A[h] to B
h++;
t++;
}
}
//address the left data
while (l <= k)//if the left have left data
{
B[t] = A[l];
l++;
t++;
}
while (h <= j)//if the right have left data
{
B[t] = A[h];
h++;
t++;
}
memcpy(A+i,B,(j-i+1)*sizeof(elem_type));//make B copy to A
free(B);//free the space
}
思想:划分递归求解。将每个数组递归的分为两个数字排序至不能再分,再逐个拷贝回原数组。该实现要注意动态内存的申请和释放。
2.2.2快速排序算法
#include <stdio.h>
#include <stdlib.h>
#include "sort.h"
void partition_sort( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
if(j<=i) return;
int partition( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *));
int k= partition(i,j,A,cmp);
partition_sort(i,k-1,A,cmp);
partition_sort(k+1,j,A,cmp);
}
int partition( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
int low = i+1;//get A[i] to be the stander
int high = j;
while (low<high)
{
while ((cmp(A+i,A+low)>=0) && low<=j)//to search the first data that biger then A[i]
{
low++;
}
while ((cmp(A+high,A+i)>=0)&& high>i)//to search the first data that smaller then A[i]
{
high--;
}
if (low<high)
{
swap(A, low, high);
} //swap the A[low] and A[high]
}
swap(A, i, high);//make A[i] to the correct place
return high;//return the position of A[i]
}
思想:仍是分治,但不再需要额外的空间。定义两个指针指示最大值和最小值,确定一个起始位置,依次向左向右搜索第一个比起始数据大的数,交换位置,直至两个指针相遇,此时得到数组的中位数。
2.2.3堆排序算法
#include <stdio.h>
#include <stdlib.h>
#include "sort.h"
void heap_sort ( int n,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
void Build_Max_Heap (elem_type *A, int n,int(*cmp)(elem_type *,elem_type *));
void Max_Heapify(elem_type *A, int n, int i,int(*cmp)(elem_type *,elem_type *));
Build_Max_Heap(A,n,cmp);
for(int i= n-1; i>0; i--)
{
swap(A, 0, i);//change the root and the last kid
Max_Heapify(A, i, 0,cmp);//make other roots be the max heap
}
}
void Build_Max_Heap (elem_type *A, int n,int(*cmp)(elem_type *,elem_type *))
{
void Max_Heapify(elem_type *A, int n, int i,int(*cmp)(elem_type *,elem_type *));
for(int i= n/2-1; i>=0; i--)
{
Max_Heapify(A, n, i,cmp);//build the max heap
}
}
void Max_Heapify(elem_type *A, int n, int i,int(*cmp)(elem_type *,elem_type *))//make father biger than their kids
{
int max=0;
int l = 2*i+1;//left kid
int r = 2*i+2;//right kid
if (l<n && (cmp(A+l,A+i)>0))//left kid biger the father
{
max = l; //get left kid
}
else
{
max = i;//get father
}
if (r<n && (cmp(A+r,A+max)>0))
{
max = r; //get right kid
}
if (max != i)
{
swap(A, i, max);//make father biger than his left and right kid
Max_Heapify(A, n, max,cmp);//until all fathers biger than their kids
}
}
思想:①最大堆的维护:比较父节点和两个子节点的大小,如孩子大则交换父子节点数据②堆排序:将数组维护成最大堆后。交换根节点和最后一个节点,排除最后一个节点再维护成最大堆
2.3 算法性能比较
2.3.1数量级10000上的性能比较
![]() |
2.3.3数量级1000000上的性能比较
附:源码
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#define INT 0
#define FLOAT 1
#define DOUBLE 2
#define STUDENT 3
#define Debug
typedef struct STU
{
char id[20];
char name[20];
float score[5];
float total;
}STU;
typedef STU elem_type;
int dataType = STUDENT;
void selection_sort(int n,elem_type *A,int (*cmp)(elem_type *,elem_type *));
void insert_sort(int n,elem_type *A,int (*cmp)(elem_type*,elem_type*));
void bubble_sort(int n,elem_type *A,int(*cmp)(elem_type *,elem_type *));
void merge_sort(int i,int j,elem_type *A,int(*cmp)(elem_type *,elem_type *));
void partition_sort( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *));
void heap_sort ( int n,elem_type *A,int(*cmp)(elem_type *,elem_type *));
//you must specify a int to indicate the data type to be sorted
//utilites to be used in main
//provide compare function
int cmp(elem_type * a, elem_type *b);
//to generate random data
void generateData(elem_type * A, int num);
void randName(char * name);
void randID(char * id);
//to output small array in debug
void output(elem_type A[],int n, char * info);
int main(int argc, char ** argv)
{
size_t t1, t2;
int size;
elem_type *orig, *toSort;
int (*cmpare)(elem_type * a, elem_type *b);
cmpare = &cmp;
if(argc<2)
return 1;
sscanf(argv[1], "%d", &size);
if(size<=0)
return 0;
orig = (elem_type*) malloc(sizeof(elem_type)*size);
toSort = (elem_type*) malloc(sizeof(elem_type)*size);
//test the selection sort
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(elem_type));
output(toSort, size,"SelectSort: before");
t1 = clock();
selection_sort(size,toSort,cmpare);
t2 = clock();
output(toSort, size, "SelectSort: after");
printf("SelectSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
//test the insert sort
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(elem_type));
output(toSort, size,"InsertSort: before");
t1 = clock();
insert_sort(size,toSort,cmpare);
t2 = clock();
output(toSort, size, "InsertSort: after");
printf("InsertSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
//test the bubble sort
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(elem_type));
output(toSort, size,"BubbleSort: before");
t1 = clock();
bubble_sort(size,toSort,cmpare);
t2 = clock();
output(toSort, size, "BubbleSort: after");
printf("BubbleSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
//test the merge sort
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(elem_type));
output(toSort, size,"MergeSort: before");
t1 = clock();
merge_sort(0,size-1,toSort,cmpare);
t2 = clock();
output(toSort, size, "MergeSort: after");
printf("MergeSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
//test the partition sort
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(elem_type));
output(toSort, size,"PartitionSort: before");
t1 = clock();
partition_sort(0,size-1,toSort,cmpare);
t2 = clock();
output(toSort, size, "Partiton: after");
printf("PartitionSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
//test the heap sort
generateData(orig, size);
memcpy(toSort, orig, size*sizeof(elem_type));
output(toSort, size,"HeapSort: before");
t1 = clock();
heap_sort(size,toSort,cmpare);
t2 = clock();
output(toSort, size, "HeapSort: after");
printf("HeapSort runs in %f seconds for %d objects\n", (t2-t1)/((double)CLOCKS_PER_SEC), size);
return 1;
}
int cmp(elem_type * a, elem_type *b)
{
if(dataType == INT)
{
if(*((int*)a) == *((int*)b))
return 0;
else if (*((int*)a)> *((int*)b))
return 1;
else
return -1;
}
else if(dataType == FLOAT)
{
if(*((float*)a) == *((float*)b))
return 0;
else if (*((float*)a)> *((float*)b))
return 1;
else
return -1;
}
else if(dataType == DOUBLE)
{
if(*((double*)a) == *((double*)b))
return 0;
else if (*((double*)a)> *((double*)b))
return 1;
else
return -1;
}
else
{
STU * pa = (STU *)a;
STU * pb = (STU *)b;
if(pa->total == pb->total)
return 0;
else if (pa->total > pb->total)
return 1;
else
return -1;
}
}
void generateData(elem_type * A, int num)
{
if(dataType == INT)
{
for(int i=0; i<num; i++)
{
*((int*)(A+i)) = rand()%(10*num);
}
}
else if(dataType == FLOAT)
{
for(int i=0; i<num; i++)
{
*((float*)(A+i)) = rand()%(10*num);
}
}
else if(dataType == DOUBLE)
{
for(int i=0; i<num; i++)
{
*((double*)(A+i)) = rand()%(10*num);
}
}
else
{
for(int i=0; i<num; i++)
{
randID(((STU*)(A+i))->id);
randName( ((STU*)(A+i))->name);
((STU*)(A+i))->total = 0;
for(int j=0; j<5; j++)
{
((STU*)(A+i))->score[j] = (rand()%10000)/((double) 100);
((STU*)(A+i))->total += ((STU*)(A+i))->score[j];
}
}
}
}
void randName(char * name)
{
char ALPHA[26]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char alpha[26]="abcdefghijklmnopqrstuvwxyz";
int len = 1+ rand()%18;
name[0] = ALPHA[rand()%26];
for(int i=1; i<len; i++)
{
name[i] = alpha[rand()%26];
}
name[len] = '\0';
}
void randID(char * id)
{
char buf[20] = "2021152";
char buf1[3];
char buf2[5];
int classNo = rand()%100;
int stuNo = rand()%10000;
sprintf(buf1, "%02d", classNo);
buf1[2] = '\0';
sprintf(buf2, "%04d", stuNo);
buf2[4] = '\0';
strcat(buf, buf1);
strcat(buf, buf2);
strcpy(id, buf);
}
void output(elem_type A[],int n, char * info)
{
printf("%s\n", info);
switch(dataType)
{
case INT:
for(int i=0; i<n; i++)
{
printf("%d ", *((int*)(A+i)));
}
printf("\n");
break;
case FLOAT:
for(int i=0; i<n; i++)
{
printf("%f ", *((float*)(A+i)));
}
printf("\n");
break;
case DOUBLE:
for(int i=0; i<n; i++)
{
printf("%f ", *((double*)(A+i)));
}
printf("\n");
break;
case STUDENT:
for(int i=0; i<n; i++)
{
printf("%s %-20s ", ((STU*)(A+i))->id, ((STU*)(A+i))->name);
for(int j=0; j<5; j++)
{
printf("%f ", ((STU*)(A+i))->score[j]);
}
printf("%f \n", ((STU*)(A+i))->total);
}
break;
default:
break;
}
}
void swap(elem_type *A, int i, int j)
{
elem_type tmp = *(A+i);
*(A+i) = *(A+j);
*(A+j) = tmp;
}
//input:the scale of array n,the array which need sort A,two pointers point to the array
//output:null
//function:manage selcect sort
void selection_sort(int n,elem_type *A,int (*cmp)(elem_type *,elem_type *))
{
for(int i = 0; i<n;i++)
{
int j=i;
for(int k=i+1;k<n;k++)
{
if(cmp(A+j,A+k)>0)
j=k;
}
swap(A,i,j);
}
}
void insert_sort(int n,elem_type *A,int (*cmp)(elem_type*,elem_type*))
{
for(int i=0;i<n;i++)
{
elem_type temp = *(A+i);
elem_type *tp = &temp;
int k=i-1;
while(cmp(A+k,tp)>0&&k>=0)
{
A[k+1]=A[k];
k--;
}
A[k+1]=temp;
}
}
void bubble_sort(int n,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n-i-1;j++)
{
if(cmp(A+j,A+j+1)>0)
swap(A,j,j+1);
}
}
}
void merge_sort(int i,int j,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
if(j<=i)return;
int k=(i+j)/2;
merge_sort(i,k,A,cmp);
merge_sort(k+1,j,A,cmp);
int l=i;
int h=k+1;
int t=0;
elem_type *B=(elem_type *)(malloc((j-i+1)*sizeof(elem_type)));
if(B==NULL)//check the return value of malloc to avoid error
{printf("memory get wrong!\n");
return;}
while(l<=k&&h<=j)
{
if(cmp(A+h,A+l)>0)
{
B[t]=A[l];
l++;
t++;
}
else
{
B[t]=A[h];
h++;
t++;
}
if(l<=k) memcpy(B+t,A+l,(k-l+1)*sizeof(elem_type));
if(h<=j) memcpy(B+t,A+k+1+h,(j-h+1)*sizeof(elem_type));
}
memcpy(A+i,B,(j-i+1)*sizeof(elem_type));
free(B);
}
void partition_sort( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
if(j<=i) return;
int partition( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *));
int k= partition(i,j,A,cmp);
partition_sort(i,k-1,A,cmp);
partition_sort(k+1,j,A,cmp);
}
int partition( int i, int j,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
int low = i+1;
int high = j;
while (low<high)
{
while ((cmp(A+i,A+low)>=0) && low<=j)
{ low++;}
while ((cmp(A+high,A+i)>=0)&& high>i)
{ high--;}
if (low<high)
{ swap(A, low, high);}
}
swap(A, i, high);
return high;
}
void heap_sort ( int n,elem_type *A,int(*cmp)(elem_type *,elem_type *))
{
void Build_Max_Heap (elem_type *A, int n);
void Max_Heapify(elem_type *A, int n, int i,int(*cmp)(elem_type *,elem_type *));
Build_Max_Heap(A,n);
for(int i= n-1; i>0; i--)
{
swap(A, 0, i);
Max_Heapify(A, i, 0,cmp);
}
}
void Build_Max_Heap (elem_type *A, int n)
{
void Max_Heapify(elem_type *A, int n, int i,int(*cmp)(elem_type *,elem_type *));
for(int i= n/2-1; i>=0; i--)
{
Max_Heapify(A, n, i,cmp);
}
}
void Max_Heapify(elem_type *A, int n, int i,int(*cmp)(elem_type *,elem_type *))
{
int max=0;
int l = 2*i+1;
int r = 2*i+2;
if (l<n && (cmp(A+l,A+i)>0))
{
max = l;
}
else
{
max = i;
}
if (r<n && (cmp(A+r,A+max)>0))
{
max = r;
}
if (max != i)
{
swap(A, i, max);
}
Max_Heapify(A, n, max,cmp);
}