冒泡排序、快速排序、基数排序、计数排序算法性能分析
来源:互联网 发布:域名一定要备案吗 编辑:程序博客网 时间:2024/05/21 17:23
- 实验要求
1) 排序n个元素,元素为随机生成的1到65535之间的整数,n的取值为: 2^2,2^5,2^8,2^11,2^14,2^17 ;
2) 算法:冒泡排序,快速排序,基数排序,计数排序;
3) 对结果进行性能分析。 - 实验环境
1) 编译环境:Dev-C++ 5.9.2
2) 机器内存:8G
3) 时钟主频:2.2GHz - 实验过程
1) 实现getnums函数(input.cpp源码在文件夹input中),随机产生2^17个1~65535间的整数,将整数写入文件input_numbers.txt中;
2) 实现冒泡排序BubbleSort.cpp,其中产生不同规模下冒泡排序的结果result_n.txt和运行时间time.txt;
3) 实现快速排序QuickSort.cpp,其中产生不同规模下快速排序的结果result_n.txt和运行时间time.txt;
4) 实现基数排序MergeSort.cpp,其中产生不同规模下基数排序的结果result_n.txt和运行时间time.txt;
5) 实现计数排序QuickSort.cpp,其中产生不同规模下计数排序的结果result_n.txt和运行时间time.txt;
6) 进行结果分析。 - 实验关键代码截图
1) getnums函数实现思路:产生2^17个1~65535间的随机数字写入input_numbers.txt中,数字间以换行间隔。
void getnums(){ FILE *fp; int i,slen,j; int temp; srand((unsigned)time(NULL)); fp = fopen("input_numbers.txt", "w"); for (i = 0; i < NUM; i++) { temp = rand()*rand() % 65535 + 1; fprintf(fp,"%d",temp); fputc('\n',fp); } fclose(fp); }
2) 记录运行时间的方法(级别us):
#include "windows.h"static LARGE_INTEGER Freq;static LARGE_INTEGER start;static LARGE_INTEGER end;static double dt;//用于计时void count_start(){ QueryPerformanceFrequency(&Freq); QueryPerformanceCounter(&start);}double count_stop(){ QueryPerformanceCounter(&end); dt = (end.QuadPart - start.QuadPart)/(double)(Freq.QuadPart); return dt;}
3) 冒泡排序过程
a)从输入数据input_numbers.txt中读取前num(问题规模)个数字存入numtemp[num]中(先读取一行数字字符串,再用函数atoi()将读的字符串转成整型数)
fp = fopen("..\\\\input\\input_numbers.txt","r");rewind(fp);memset(numtemp,0,num*sizeof(int));for(j = 1; j <= num; j++){ memset(strtemp[j],0,7*sizeof(char)); fscanf(fp,"%s",strtemp[j]); numtemp[j] = atoi(strtemp[j]); }fclose(fp);
b) 实现冒泡排序的过程(swap实现交换两个数字的功能,起始用上述记录时间的方法来记录运行时间)
count_start(); //开始排序for(i = num-1; i > 1; i--){ for(j = 1; j <= i; j++) {//每次将小的数往前调整 if(numtemp[j] > numtemp[j+1]) swap(&numtemp[j], &numtemp[j+1]); }}dtime[k] = count_stop();//结束排序
swap:
void swap(int *a,int *b){ int temp = *a; *a = *b; *b = temp;}
c) 将排序结果进行文件result_n.txt中
fp1 = fopen(name[k],"w");for(i = 1; i <= num; i++){ fprintf(fp1,"%d",numtemp[i]); fputc('\n',fp1);}fclose(fp1);
d) 运行BubbleSort.cpp
4) 快速排序算法的实现:
a) 从input_numbers.txt中读取数据(方法同上)
b) 快速排序过程:
count_start();//开始排序 QuickSortRecur(numtemp,1,num);dtime[k] = count_stop();//结束排序
void QuickSortRecur(int a[],int p, int r){//递归过程 int q; if(p < r) { q = Partition(a, p, r);//分区 QuickSortRecur(a, p, q-1);//分区左边排序 QuickSortRecur(a, q+1, r);//分区右边进行排序 }}
c) Partition过程:
int Partition(int a[],int p,int r){//以a[r]为标记界限,比a[r]小的放在前面,比a[r]大的放在后面,返回分界点 int i,j,temp; temp = a[r]; i = p - 1; for(j = p; j <= r-1; j++) { if(a[j] < temp) { i++; swap(&a[i], &a[j]); } } swap(&a[i+1], &a[r]); return i+1;}
d) 将运行结果写入result_n.txt中。
5) 计数排序算法的实现:
a) 从input_numbers.txt中读取数据(方法同上)
b) 计数排序过程(排序结果返回给result):
count_start(); //开始排序result = _CountingSort(numtemp,num);//结束排序dtime[k] = count_stop();
_CountingSort()的实现如下:
int* _CountingSort(int a[],int num){//返回排好序的数组 int range = 65535; int C[range + 1]; int temp[num]; int i,j; for(i = 0; i <= range; i++) C[i] = 0; for(j = 1; j <= num; j++) { C[a[j]] = C[a[j]] + 1; } for(i = 0; i <= range; i++) { C[i] = C[i] + C[i - 1]; } for(j = num; j > 0; j--) { temp[C[a[j]]] = a[j]; C[a[j]] = C[a[j]] - 1; } return temp;}
c) 运行结果
6) 基数排序算法的实现:
a) 从input_numbers.txt中读取数据(注:这里并不是将数字存入一维整型数组中,而是将每个数字按数位拆分(SplitDigit函数)后,存入二维数组numtemp[num][6]中,以便于后续对每一个十进制位使用计数排序进行排序):
fp = fopen("..\\\\input\\input_numbers.txt","r");rewind(fp); for(j = 1; j <= num; j++){//从输入数据中读取一行,并将该行数据拆分出每一位 memset(numtemp[j],0,6*sizeof(int)); memset(strtemp[j],0,7*sizeof(char)); fscanf(fp,"%s",strtemp[j]); splitnum = SplitDigit(strtemp[j]); for(i = 0; i < 5; i++) { numtemp[j][i] = *(splitnum + i); } }fclose(fp);
函数SplitDigit的实现是:将从文件中读取一行得到的字符串,从个位开始到十位、百位、千位、万位,每一位都减去数字0的ASCII码存入一维数组digit中,返回digit
int* SplitDigit(char str[7]){ int digit[5]; int i,j; for(i = 0; i < 5; i++) digit[i] = 0; j = 4; int len = strlen(str); for(i = len - 1; i >= 0; i--) { if(j >= 0) { digit[j] = (int)str[i] - 48; j--; } } return digit;}
b) 基数排序过程:
i. 这里从个位的排序开始,调用3)中的计数排序算法(额外输入上一个位数排序之后各个元素在原数组中的下标index[],返回的是排序后的数组元素在原数组中的下标,而不是排好序后的数组,即每位排序不直接改变原数组,而是记录下来排序后的元素在原数组中的下标,最后再一次性调整);
index初值为:
for(i = 0; i <= num; i++) { index[i] = i; }
ii. 取每一个数的第i位存入数组digitsort中
这里便是取每个数的个位数存入digitsort,使用上述的初始index进行计数排序,返回结果为按个位数从小到大排列的元素在原数组numtemp中的下标:
for(j = 1; j <= num; j++){ digitsort[j] = numtemp[j][4];}result = _CountingSort(digitsort,index,num);
int* _CountingSort(int a[],int index[], int num){ int range = 65535; int C[range + 1]; int temp[num + 1]; int i,j; for(i = 0; i <= range; i++) C[i] = 0; for(j = 1; j <= num; j++) { C[a[j]] = C[a[j]] + 1; } for(i = 0; i <= range; i++) { C[i] = C[i] + C[i - 1]; } for(j = num; j > 0; j--) { temp[C[a[j]]] = index[j]; /////// C[a[j]] = C[a[j]] - 1; } return temp;}
iii. 再依次按照十位、百位、千位、万位进行排序,排序前根据上一次返回的result进行index的调整(表明index是经前面几个位数的排序后各个元素在原数组的下标):
for(i = 3; i >= 0; i--) { for(j = 1; j <= num; j++) { index[j] = *(result + j); digitsort[j] = numtemp[*(result+j)][i]; } result = _CountingSort(digitsort,index,num); }
iv. 排序完成之后,可以将numtemp中的元素合并成一维整型数组mergenum,再根据result中的下标,依次的从mergenum中取相应下标的数放入sortnum中,得到最终的结果即为sortnum:
mergenum = MergeDigit(numtemp,num); for(i = 1; i <= num; i++){ sortnum[i] = mergenum[*(result + i)];}
函数MergeDigit的实现(按位数乘以位权重求和即可):
int* MergeDigit(int (*a)[6],int num){ int result[num + 1]; int i; for(i = 1; i <= num; i++) { result[i] = a[i][0]*10000 + a[i][1]*1000 + a[i][2]*100 + a[i][3]*10 + a[i][4]; } return result;}
c) 运行结果
- 实验结果、分析(结合相关数据图表分析)
1) 冒泡排序结果分析(工具:Excel):
基本符合O(n2)的算法复杂度
2) 快速排序结果分析(excel中没有nlgn的拟合,故用origin8进行)
基本符合O(nlgn)的算法复杂度
3) 计数排序结果分析(当n比较小时,由于k很大为65535,导致运行时间并不线性,故将n在2^14和2^17间增加了四个点来进行分析)如下:
对结果的分析:
基本符合O(n+k)的算法复杂度
4) 基数排序结果分析(由于用了计数排序,故当n远小于k时,运行时间并不成线性,故增加了几个点来进行分析)如下:
基本符合O(n+k)的算法复杂度
6. 实验心得
1) 当问题规模n较小时,性能:快速排序>冒泡排序>计数排序>基数排序,当问题规模n较大时,性能:计数排序>快速排序>基数排序>冒泡排序;
2) 对四种排序的算法和性能有了更深入的了解,尤其是基数排序的实现模块思考了很久,学习了在不同问题规模下和处理不同类型的数据下,该如何选择最优的算法;
3) 对文件读写操作更为熟练;
4) 学会了使用excel和origin等数据分析工具进行性能的分析过程。
源代码下载:http://download.csdn.net/download/m0_37829610/10025689
转载请注明出处:
http://blog.csdn.net/m0_37829610/article/details/78268531
- 冒泡排序、快速排序、基数排序、计数排序算法性能分析
- C++算法 冒泡排序,快速排序,插入排序,希尔排序,计数排序,基数排序 性能比较
- 【更新】排序算法比较:插入排序,冒泡排序,归并排序,堆排序,快速排序,计数排序,基数排序,桶排序
- 排序算法(插入排序、shell排序、冒泡排序、选择排序、合并排序、堆排序、快速排序、计数排序、基数排序、桶排序)
- 排序算法----冒泡排序+插入排序+选择排序+快速排序+希尔排序+堆排序+归并排序+计数排序+基数排序+桶排序(c语言)
- 基础排序算法总结(插入、选择、冒泡、合并、二分查找、堆排序、快速排序、基数排序、桶排序、计数排序)
- 经典排序算法设计与分析(插入排序、冒泡排序、选择排序、shell排序、快速排序、堆排序、分配排序、基数排序、桶排序、归并排序)
- 经典排序算法设计与分析(插入排序、冒泡排序、选择排序、shell排序、快速排序、堆排序、分配排序、基数排序、桶排序、归并排序)
- 算法导论(3) 快速排序、计数排序、基数排序
- 算法导论之排序:快速排序、归并排序、计数排序、基数排序、桶排序
- 冒泡排序、选择排序、插入排序、快速排序算法的时间性能分析(java实现)
- 【算法】排序 (二):冒泡排序&快速排序&归并排序&基数排序&拓扑排序(C++实现)
- 排序算法之计数&基数排序
- 各种排序算法总结----基数排序、归并排序、插入排序、冒泡排序、选择排序、快速排序、堆排序、希尔排序
- 数组排序 —— 常用基础数组排序算法(冒泡、选择、插入、归并、快速、堆、希尔、计数、基数排序)
- 计数排序,基数排序,桶排序算法
- 已完成以下算法:冒泡排序,插入排序,希尔排序,快速排序,基数排序
- 排序算法(2)冒泡排序,快速排序,归并排序和基数排序MSD,LSD
- Logstash学习18_Logstash Sqlite input plugin 插件离线安装
- jQuery总结:一、选择器
- libevent源码阅读笔记
- 他用AI入侵手机 给你定制“女友”!
- 智东西「自动驾驶」微信社群开放申请 10月4堂系列课重磅开讲
- 冒泡排序、快速排序、基数排序、计数排序算法性能分析
- 待解决疑问
- 专访 | 袋鼠云CEO:靠数据智能两年融资过亿,拉来茅台京东方做客户
- 华为发布Mate10 5400元起售 戴姆勒将大规模重组 分拆汽车和卡车业务
- 深度学习基础介绍
- linux-alias的使用(定义自己习惯的命令)
- 社交化ERP与大数据的整合
- gradle3.3网盘下载,超快
- [Lintcode] #82 落单的数