对字符串进行直接插入排序、堆排序、归并排序、快速排序实现以及性能分析
2017-10-17 12:15
656 查看
实验要求
1) 排序 n 个元素,元素为随机生成的长为1..32的字符串(字符串均为英文小写字母),n的取值为:2^2,2^5,2^8,2^11,2^14,2^17;
2) 算法:直接插入排序,堆排序,归并排序,快速排序;
3) 字符串大小判断标准:首先按字符串长度进行排序(短字符串在前,长字符串在后)。然后对长度相同的字符串,按字母顺序进行排序;
4) 对结果进行性能分析。
实验环境
1) 编译环境:Dev-C++ 5.9.2
2) 机器内存:8G
3) 时钟主频:2.2GHz
实验过程
1) 实现getstrs函数(input.cpp源码在文件夹input中),随机产生2^17个均为小写字母的字符串,将字符串写入文件input_strings.txt中;
2) 实现插入排序StraightInsertSort.cpp,其中产生不同规模下插入排序的结果result_n.txt和运行时间time.txt;
3)实现堆排序HeapSort.cpp,其中产生不同规模下堆排序的结果result_n.txt和运行时间time.txt;
4) 实现归并排序MergeSort.cpp,其中产生不同规模下归并排序的结果result_n.txt和运行时间time.txt;
5) 实现快速排序QuickSort.cpp,其中产生不同规模下快速排序的结果result_n.txt和运行时间time.txt;
6) 进行结果分析。
实验关键代码截图
1) getstrs函数实现思路:每个字符串都是先产生一个随机长度,然后产生长度个随机字符写入input_strings.txt中,字符串间以换行间隔。
2) 记录运行时间的方法(级别us):
3) 插入排序过程
a) 从输入数据中读取前num (问题规模)个字符串存入strtemp[num][33]
b) 实现插入排序的过程(compare为按照长度优先、字典顺序优先的字符串比较函数,swap实现交换两个字符串的功能,起始记录时间)
compare:
swap:
c) 将排序结果进行文件result_n.txt中
4) 堆排序算法的实现:
a) 从input_strings.txt中读取数据(方法同上)
b) 堆排序过程:
c) 建堆BuildHeap过程:
d) 堆调整HeapAdjust过程(swap和compare与插入排序中的一样):
e) 将运行结果写入文件中。
5) 归并排序算法的实现:
a) 从input_strings.txt中读取数据(方法同上)
b) 归并排序过程(递归执行):
c) PreMerge过程(将p到q和q+1到r两部分合并到a中):
i. 先将a[p..q]复制给L[1..nums1],将a[q+1..r]复制给R[1..nums2];
ii. 由于在执行PreMerge之前已经对a[p..q]和a[q+1,r]进行了Merge操作,故此时L和R中均为已排好序的数组
iii. 依次比较L[i]和R[j],将较小的写入a[k]中;
iv. 将L或R中剩余的元素复制到a中。
d) 运行结果写入文件
6) 快速排序算法的实现:
a) 从input_strings.txt中读取数据(方法同上)
b) 快速排序过程:
c) Partition过程(取a[r]为标记位):
d) 运行结果写入文件
5. 实验结果、分析(结合相关数据图表分析)
1) 直接插入排序结果分析(工具:Excel):
基本符合O(n2)的算法复杂度
2) 堆排序结果分析(发现excel中没有nlgn的拟合,故用origin8进行)
基本符合O(nlgn)的算法复杂度
3) 归并排序结果分析
基本符合O(nlgn)的算法复杂度
4) 快速排序结果分析
基本符合O(nlgn)的算法复杂度
6. 实验心得
1) 对直接插入排序、堆排序、归并排序、快速排序的算法及其性能有了更深入的了解,学会了四种不同排序算法的实现,在性能分析上,后三个算法的时间性能明显优于直接插入排序,快速排序比堆排序和归并排序性能稍优一点,而归并排序需要多占用一倍的存储空间(本实验中,尚未考虑到存储空间限制的情况);
2) 对文件读写操作更为熟练;
3) 学会了使用excel和origin等数据分析工具进行性能的分析过程。
实验源代码:
http://download.csdn.net/download/m0_37829610/10025033
转载请注明出处:
http://blog.csdn.net/m0_37829610/article/details/78259022
1) 排序 n 个元素,元素为随机生成的长为1..32的字符串(字符串均为英文小写字母),n的取值为:2^2,2^5,2^8,2^11,2^14,2^17;
2) 算法:直接插入排序,堆排序,归并排序,快速排序;
3) 字符串大小判断标准:首先按字符串长度进行排序(短字符串在前,长字符串在后)。然后对长度相同的字符串,按字母顺序进行排序;
4) 对结果进行性能分析。
实验环境
1) 编译环境:Dev-C++ 5.9.2
2) 机器内存:8G
3) 时钟主频:2.2GHz
实验过程
1) 实现getstrs函数(input.cpp源码在文件夹input中),随机产生2^17个均为小写字母的字符串,将字符串写入文件input_strings.txt中;
2) 实现插入排序StraightInsertSort.cpp,其中产生不同规模下插入排序的结果result_n.txt和运行时间time.txt;
3)实现堆排序HeapSort.cpp,其中产生不同规模下堆排序的结果result_n.txt和运行时间time.txt;
4) 实现归并排序MergeSort.cpp,其中产生不同规模下归并排序的结果result_n.txt和运行时间time.txt;
5) 实现快速排序QuickSort.cpp,其中产生不同规模下快速排序的结果result_n.txt和运行时间time.txt;
6) 进行结果分析。
实验关键代码截图
1) getstrs函数实现思路:每个字符串都是先产生一个随机长度,然后产生长度个随机字符写入input_strings.txt中,字符串间以换行间隔。
void getstrs() { FILE *fp; int i,slen,j; char temp; srand((unsigned)time(NULL)); fp = fopen("input_strings.txt", "w"); for (i = 0; i < NUM; i++) { slen = rand()*rand() % 32 + 1; for (j = 0; j < slen; j++) { temp = 'a' + rand()*rand() % 26; fputc(temp,fp); } 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) 从输入数据中读取前num (问题规模)个字符串存入strtemp[num][33]
fp = fopen("..\\\\input\\input_strings.txt","r"); rewind(fp); for(j = 0; j < num; j++) {//从输入数据中读取字符串 memset(strtemp[j],0,33*sizeof(char)); fscanf(fp,"%s",strtemp[j]); } fclose(fp);
b) 实现插入排序的过程(compare为按照长度优先、字典顺序优先的字符串比较函数,swap实现交换两个字符串的功能,起始记录时间)
count_start();//排序开始 for(j = 1; j < num; j++) {//从第一个开始,依次调整j以前的所有元素的顺序 i = j - 1; strcpy(key,strtemp[j]); while(i >= 0) { if(!(compare(key,strtemp[i]))) {//逐步往后移直到找到正确的位置 swap(strtemp[i],strtemp[i+1]); i--; } else break; } strcpy(strtemp[i+1],key); } dtime[k] = count_stop();//排序结束
compare:
int compare(char a[33], char b[33]) { int len1 = strlen(a); int len2 = strlen(b); if(len1 < len2) { return 0; } else if(len1 == len2) { if(strcmp(a,b) < 0) { return 0; } else return 1; } }
swap:
void swap(char a[33], char b[33]) { char temp[33]; strcpy(temp,a); strcpy(a,b); strcpy(b,temp); }
c) 将排序结果进行文件result_n.txt中
for(i = 0; i < num; i++) {//排序结果写进相应文件 fputs(strtemp[i],fp1); fputc('\n',fp1); }
4) 堆排序算法的实现:
a) 从input_strings.txt中读取数据(方法同上)
b) 堆排序过程:
count_start();//排序开始 BuildHeap(strtemp,num); for(i = num;i >= 2; i--) { swap(strtemp[1],strtemp[i]); HeapAdjust(strtemp,1,i-1); } dtime[k] = count_stop();//排序结束
c) 建堆BuildHeap过程:
void BuildHeap(char (*a)[33],int size) {//建堆 int i; for(i = size/2;i >= 1; i--) {//从第一个非叶节点开始进行堆调整 HeapAdjust(a,i,size); b862 } }
d) 堆调整HeapAdjust过程(swap和compare与插入排序中的一样):
void HeapAdjust(char (*a)[33],int i,int size) {//堆调整过程 int lchild = 2*i; int rchild = 2*i + 1; int max = i; char temp[33]; if(i <= size/2) { if(lchild <= size && !(compare(a[max],a[lchild]))) {//跟左孩子的值比较 max = lchild; } if(rchild <= size && !(compare(a[max],a[rchild]))) {//跟右孩子的值比较 max = rchild; } if(max != i) {//交换调整 swap(a[i],a[max]); HeapAdjust(a,max,size);//递归调整 } } }
e) 将运行结果写入文件中。
5) 归并排序算法的实现:
a) 从input_strings.txt中读取数据(方法同上)
b) 归并排序过程(递归执行):
count_start();//排序开始 Merge(strtemp,1,num); dtime[k] = count_stop();//排序结束
void Merge(char (*a)[33],int p,int r) { int q; if(p < r) { q = (p + r) / 2; Merge(a,p,q);//左边进行递归的归并 Merge(a,q+1,r);//右边进行递归的归并 PreMerge(a,p,q,r);//将左右两边合成一个数组 } }
c) PreMerge过程(将p到q和q+1到r两部分合并到a中):
i. 先将a[p..q]复制给L[1..nums1],将a[q+1..r]复制给R[1..nums2];
ii. 由于在执行PreMerge之前已经对a[p..q]和a[q+1,r]进行了Merge操作,故此时L和R中均为已排好序的数组
iii. 依次比较L[i]和R[j],将较小的写入a[k]中;
iv. 将L或R中剩余的元素复制到a中。
void PreMerge(char (*a)[33],int p,int q,int r) {//将两个已排好序的数组合并成一个 int nums1 = q - p + 1, nums2 = r - q; int i,j,k; for(i = 1; i <= nums1; i++) {//将a的前半部分复制到L中 memset(L[i], 0, 33*sizeof(char)); strcpy(L[i], a[p+i-1]); } for(j = 1; j <= nums2; j++) {//将a的后半部分复制到R中 memset(R[j], 0, 33*sizeof(char)); strcpy(R[j], a[q+j]); } for(k = p,i = 1,j = 1; k <= r; k++) {//逐个比较L[i]和R[j],按大小顺序复制到原数组中 if(i <= nums1 && j <= nums2) { if(!(compare(L[i],R[j]))) strcpy(a[k],L[i++]); else strcpy(a[k],R[j++]); } else if(i > nums1)//剩余元素复制到a中 strcpy(a[k],R[j++]); else strcpy(a[k],L[i++]); } }
d) 运行结果写入文件
6) 快速排序算法的实现:
a) 从input_strings.txt中读取数据(方法同上)
b) 快速排序过程:
count_start();//排序开始 QuickSortRecur(strtemp,1,num); dtime[k] = count_stop();//排序结束
void QuickSortRecur(char (*a)[33],int p, int r) {//递归进行排序 int q; if(p < r) { q = Partition(a,p,r);//以a[r]为标记进行分区 QuickSortRecur(a,p,q-1);//分区左边进行快排 QuickSortRecur(a,q+1,r);//分区右边进行快排 } }
c) Partition过程(取a[r]为标记位):
int Partition(char (*a)[33],int p,int r) { char temp[33]; int i,j; strcpy(temp,a[r]); i = p - 1; for(j = p; j <= r-1; j++) {//将每个树与a[r]进行比较 if(!(compare(a[j],temp))) { i++; swap(a[i],a[j]); } } swap(a[i+1],a[r]); return i+1; }
d) 运行结果写入文件
5. 实验结果、分析(结合相关数据图表分析)
1) 直接插入排序结果分析(工具:Excel):
基本符合O(n2)的算法复杂度
2) 堆排序结果分析(发现excel中没有nlgn的拟合,故用origin8进行)
基本符合O(nlgn)的算法复杂度
3) 归并排序结果分析
基本符合O(nlgn)的算法复杂度
4) 快速排序结果分析
基本符合O(nlgn)的算法复杂度
6. 实验心得
1) 对直接插入排序、堆排序、归并排序、快速排序的算法及其性能有了更深入的了解,学会了四种不同排序算法的实现,在性能分析上,后三个算法的时间性能明显优于直接插入排序,快速排序比堆排序和归并排序性能稍优一点,而归并排序需要多占用一倍的存储空间(本实验中,尚未考虑到存储空间限制的情况);
2) 对文件读写操作更为熟练;
3) 学会了使用excel和origin等数据分析工具进行性能的分析过程。
实验源代码:
http://download.csdn.net/download/m0_37829610/10025033
转载请注明出处:
http://blog.csdn.net/m0_37829610/article/details/78259022
相关文章推荐
- 归并排序的Java实现、性能分析以及适用场景
- 排序算法的C++实现与性能分析(插入排序、归并排序、快速排序、STOOGE排序、堆排序)
- 图解Arraylist内存分配,以及底层实现,扩容性能分析
- 插入排序、选择排序、归并排序、堆排序、快速排序的JAVA实现
- oracle实现分页以及性能分析
- C++ 实现堆排序 归并排序 快速排序
- TraceView-对Android的应用程序以及Framework层的代码进行性能分析
- 算法导论之插入排序,选择排序,归并排序,冒泡排序,希尔排序,堆排序,快速排序的c语言实现
- 插入排序和归并排序实现以及时间复杂度分析
- [疯狂Java]集合:Deque(双端队列)以及两个实现(ArrayDeque、LinkedList)、Stack(摒弃)、各线性表性能分析
- java版排序算法简介及冒泡排序以及优化,选择排序,直接插入排序,希尔排序,堆排序,快速排序及其优化前言 2 分类 2 稳定性 3 时间复杂度 4 Java实现版本 5 1、冒泡排序 6 2、选择排序
- ibatis一对一、一对多实现以及性能分析
- 冒泡排序的Java实现、性能分析以及适用场景
- C++:探究纯虚析构函数以及实现数组的快速排序与链表的归并排序
- 元素排序几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- java中各种常用排序实现(直接插入排序、直接选择排序、堆排序、冒泡排序、快速排序和归并排序)
- 快速排序实现以及时间复杂度分析
- 图解Arraylist内存分配,以及底层实现,扩容性能分析
- 堆排序的JAVA实现和性能分析
- 算法导论之插入排序,选择排序,归并排序,冒泡排序,希尔排序,堆排序,快速排序的c语言实现