实验九 排序(插入和快排)

实验九 排序

完成时间】2021年1月6日

【实验要求】

(1)至少要有一种排序算法的性能优于O(n2)

(2)对实现的排序算法进行实验比较,实验比较数据参见教材7.8章节

(3)排序算法要基于教材,测试输入的整数数据文件(5个,文件中数据规模分别是100,1K,10K,100K和1M),排序结果也要输出到文件中。

(4)要在屏幕上输出排序过程所花费时间。

(5)提交最终实验作业。用附件的形式,提交两个文件:一个压缩包(包含源码和5个用于排序测试的数据文件);一个pdf文档(文档中包含实验日志和一个根据基本要求(1)记录实验结果的表格,然后进行适当的实验结果分析)。

【实验构想】

本次采用快速排序和插入排序两种方法进行实验。在实验前分析,快速排序的速度应该高于插入排序,事实也证明了我的这一想法。
同时,
可以先看一下,各种排序算法性能比较
在这里插入图片描述
在此说一下快排。
动机:
分治思想:划分交换排序
基本思想:
在待排序记录中选取一个记录R(称为轴值pivot),
通过一趟排序将其余待排记录分割(划分)成独立
的两部分,比R小的记录放在R之前,比R大的记录
放在R之后,然后分别对R前后两部分记录继续进行
同样的划分交换排序,直至待排序序列长度等于1,
这时整个序列有序。
快速排序算法过程
快速排序过程:快速排序(划分过程)用递归实现。
若当前(未排序)序列的长度不大于1
返回当前序列
否则
在待排序记录中选取一个记录做为轴值,通过划分
算法将其余待排记录划分成两部分,比R小的记录放
在R之前,比R大的记录放在R之后;
分别用快速排序对前后两个子序列进行排序(注意轴
值已经在最终排序好的数组中的位置。无须继续处理)
快速排序算法过程(续)
选取轴值,划分序列的过程:
记录数组A,待排子序列左、右两端的下标i和j
选取待排序子序列中间位置的记录为轴值
交换轴值和位置j的值
依据在位置j的轴值,将数组i-1到j之间的待排序记录划分
为两个部分(i到k-1之间的记录比轴值小,k到j-1之间的
记录比轴值大)
从数组i-1到j之间的待排序序列两端向中间移动下标,
必要时交换记录,直到两端的下标相遇为止(相遇的位置记为k)交换轴值和位置k的值
快速排序算法举例
在这里插入图片描述
快速排序算法性能分析
时间开销:
找轴值:常数时间
划分:Θ(s),s是数列的长度
最差情况: 糟糕的分割Θ(n^2)
最佳情况: 每次将数列分割为等长的两部分 Θ(nlogn)
在这里插入图片描述
Θ(nlogn)
空间开销:
辅助栈空间,Θ(logn)
快速排序的特点
• 冒泡排序的改进,划分交换排序
• 轴值的取值影响性能
• 时间复杂度为(nlogn)
• 不稳定的排序方法
• 实际,快速排序是最好的内排序方法
快速排序的优化:
–更好的轴值
–对于小的子数列采用更好的排序算法
–用栈来模拟递归调用
【实验结果】

本次实验使用插入排序和快速排序进行测试,得到测试结果如下表所示: 单位(ms)

数据规模1001K10K100K1M
插入排序02126123971325554
快速排序00214156

【结果分析】

数据来源是Excel中的数学公式“=RANDBETWEEN()”,每次从1到最大值开始随机生成相应规模的数据,将生成好的数据导入到对应的txt文本中。

下面我们看算法,从数据大小来看,100到1M中5个样本值比较,插入排序运行时间随数据规模10倍的增大每次以接近100倍的效率进行突变,时间复杂度为O(n²),在1M时,在测试时需要等待其运算结束,具有很明显的运行时间;而快速排序,随数据规模10倍的增大每次以接近10倍的效率进行突变,对于数据规模较小的100,1k快速排序的时间代价都要小于1ms,结合测试数据总体以及理论实现快速排序的时间复杂度为O(nlogn)。

从两个算法比较来看,100,1K小样本数据中插入排序和快速排序差别不大,若结合理论来分析,在特定的原始数据特征下,插入排序比快速排序还要快一点,不过这是微秒级的差距,很微小;但是从10K往上开始两者的排序效率就开始有明显的差异,在数据规模为10k时,两者运行时间人的感知不明显,但数值上可以看到明显差距,对于100k的数据规模,快速排序仍然能够很快的出结果,但在插入排序阶段可以感知到程序在运行的时间长度,对于1M的数据规模,快速排序在极短的时间内得到结果,但插入排序则需要等候几分钟,对于相对较差的处理器来说可能要几十分钟,nlogn与n²的差距还是非常明显。
源码如下
(创建txt 文件在实验8

#include <iostream>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <sstream> 
using namespace std;
int A[1000000], B[1000000];

void swap(int A[], int i, int j) {
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

void insertsort(int A[], int n) {
    for (int i = 1; i < n; i++) {
        for (int j = i; j > 0; j--) {
            if (A[j] < A[j - 1]) {
                swap(A, j, j - 1);
            } else {
                break;
            }
        }
    }
}

void quicksort(int A[], int i, int j) {
    if (i >= j) {
        return;
    }
    int dex = (i + j) / 2;
    swap(A, dex, j);
    int l = i, r = j;
    while (l != r) {
        while (A[l] <= A[j] && l < r) {
            l++;
        }
        while (A[r] >= A[j] && l < r) {
            r--;
        }
        swap(A, l, r);
    }
    swap(A, l, j);
    quicksort(A, i, l - 1);
    quicksort(A, r + 1, j);
}

int main() {
	stringstream ss;
	string limit[5] = {"100", "1k", "10k", "100k", "1M"};
    int n = 0, k;
    double start = 0, end = 0;
    ifstream input;
    ofstream output_ins;
    ofstream output_qui;
    string order;
    for (int j = 0; j < 5; j++) {
    	n = 0;
		ss << j + 1;
		ss >> order;
		ss.clear();
	    input.open("in_" + order + ".txt");
	    output_ins.open("out_ins_" + order + ".txt");
	    output_qui.open("out_qui_" + order + ".txt");
	    while (!input.eof()){
	    	input >> k; 
	        A[n] = k;
			B[n++] = k;;
	    } 
	    cout << "当数据规模是" << limit[j] << "时:\n";
	    start = clock();
	    quicksort(B, 0, n - 1);
	    end = clock();
	    cout << "快速排序消耗时间为:" << end - start << "ms" << endl;
	    for (int i = 0; i < n; i++) {
	        output_qui << left << B[i] << "\t";
	        if (i % 10 == 0 && i != 0)
				output_qui << endl; 
	    }
	    output_qui << "快速排序消耗时间为:" << end - start << "ms" << endl;
	    start = clock();
	    insertsort(A, n);
	    end = clock();
	    cout << "插入排序消耗时间为:" << end - start << "ms" << endl ;
	    
	    for (int i = 0; i < n; i++) {
	        output_ins << left << A[i] << "\t";
	        if (i % 10 == 0 && i != 0)
				output_ins << endl; 
	    }
	    output_ins << "插入排序消耗时间为:" << end - start << "ms" << endl ;
	    input.close();
	    output_ins.close();
	    output_qui.close(); 
	}
    return 0;
}

最后是各种排序算法性能比较

最佳平均最差空间稳定性排序方法
直接插入排序nn^2n^21稳定插入
冒泡排序n^2n^2n^21稳定交换
简单选择排序n^2n^2n^21稳定选择
希尔排序nlognnlog^2 nnlog^2 n1不稳定插入
快速排序nlognnlognn^2logn~n不稳定交换
归并排序nlognnlognnlognn稳定归并
基数排序nk+rknk+rknk+rkn+2^k稳定非比较
堆排序nlognnlognnlogn1不稳定选择
桶式排序n+rn+rn+rn+r稳定非比较

时间关系不一一列举

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

savkACUNCB: IOnjn

欢迎来到我的世界

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值