算法设计与分析 实验一 排序算法性能分析(上)

简介: 算法设计与分析 实验一 排序算法性能分析(上)

一、实验目的与要求


1、实验基本要求


①掌握选择排序、冒泡排序、合并排序、快速排序、插入排序算法原理

②掌握不同排序算法时间效率的经验分析方法,验证理论分析与经验分析的一致性。


2、实验亮点


①除了基本五种排序算法,额外选择了基数排序,希尔排序和堆排序三种排序算法进行性能分析并对一些算法提出优化方案。

②使用Tableau进行绘图,完成数据可视化

③对实验过程中发现的相关问题进行了探究并解决

④分析了每一种情况下理论时间消耗与实际时间消耗偏差的原因。

⑤实现了对部分算法的优化以及思考题对一万亿数据的排序问题


二、实验内容与方法


 排序问题要求我们按照升序排列给定列表中的数据项,目前为止,已有多种排序算法提出。本实验要求掌握选择排序、冒泡排序、合并排序、快速排序、插入排序算法原理,并进行代码实现。通过对大量样本的测试结果,统计不同排序算法的时间效率与输入规模的关系,通过经验分析方法,展示不同排序算法的时间复杂度,并与理论分析的基本运算次数做比较,验证理论分析结论的正确性。


三、实验步骤与过程


(一)独立算法性能分析


1. 冒泡排序


(1)算法实现原理

①比较相邻的元素。如果第一个比第二个大,就交换他们两个。

②对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

③针对所有的元素重复以上的步骤,除了最后一个。

④持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。


 下面以使用冒泡排序3,5,1,2这四个数字为例,以图示介绍冒泡排序,见下图


1a6c8a656f7e4c42933b1be69d149ca1.png


(2)源代码


BUBBLESORT(A)
  for i = 1 to A.length-1
    for j = A.length downto i + 1
      if A[j] < A[j - 1]
        exchange A[j] with A[j - 1]


(3)算法性能分析:

①时间复杂度分析:

若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值


5d3d503570a54fcdb33b426a6ed52acd.png


所以,冒泡排序最好的时间复杂度为O ( n )

若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较( 1 ≤ i ≤ n − 1 ) ,且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:


53b220de13e04e3b96ccccb7a42f5472.png


冒泡排序的最坏时间复杂度为O ( n 2 )

综上,因此冒泡排序总的平均时间复杂度为O ( n 2 )


②数据测试分析:

使用随机数生成器生成了从102106的不同数据量级的随机数,通过使用冒泡排序进行排序并获取了程序运行时间。为降低偶然性,对20组数据取平均值,选择105 时运行时间为理论值并做表如下:

976bfb6aa97f454baf9544596c1903b8.png

通过获得的数据,使用 105

时的时间消耗为基准理论值,使用Tableau做图像并拟合如图:

e29ccdf79a7a41ccba7c503926b01484.png

  由于冒泡排序算法时间复杂度为O (n2 )  ,故,数量级扩大10倍时,时间消耗应扩大100倍。由上图,可得随着数据量的增大,拟合效果越好,所有实验数据符合O ( n 2 )  )的时间复杂度。

 从上图可知,实际时间消耗曲线与理论时间消耗基本拟合,冒泡排序算法的时间复杂度满足O (n2 )


2. 选择排序


(1)算法实现原理

①首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

②从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。

③重复上述过程直至所有元素均排序完毕。


下面以使用选择排序3,5,1,2这四个数字为例,以图示介绍选择排序,见下图

e552b4a7b46142c98e5863612ee8a13d.png


(2)源代码

SELECTSORT(ele)
  for i=0 to n-2
    min=i
    for j= i+1 to n-1
        if ele[min]>ele[j]  min=j
    swap(ele[i],ele[min])

(3)算法性能分析

①时间复杂度分析:

选择排序的交换操作介于0 00与n − 1次之间。选择排序的比较操作为n ( n − 1 ) / 2  次之间。选择排序的赋值操作介于 0 和 3 ( n − 1  次之间。比较次数为O ( n2 )

)。比较次数与关键字的初始状态无关,总的比较次数N = ( n − 1 ) + ( n − 2 ) + . . . + 1 = n ( n − 1 ) / 2 交换次数O ( n ),最好情况是,已经有序,交换0次;最坏情况交换n − 1 次,逆序交换n / 2 次。因此选择排序的时间复杂度为O ( n2 )


②数据测试分析:

使用随机数生成器生成了从102106的不同数据量级的随机数,通过使用选择排序进行排序并获取了程序运行时间。为降低偶然性,对20组数据取平均值,选择105时运行时间为理论值并做表如下:

ea188ee6d28d4e44a86d2eb34f678591.png

通过获得的数据,使用105 时的时间消耗为基准理论值,使用Tableau做图像并拟合如图:


f731f27573bd40b08e23ffa565aa848f.png


由于选择排序算法时间复杂度为O (n2 ),故,数量级扩大10倍时,时间消耗应扩大100倍。由上图,可得随着数据量的增大,拟合效果越好,所有实验数据符合O (n2 )的时间复杂度。

从上表和上图中可以发现整体时间消耗都大致满足数量级扩大10倍,时间消耗扩大100倍的规律。但对于101102

数量级时存在较大误差,拟合效果较差。通过分析可知,选择排序中进行了很多次相互调换元素(相互赋值)的操作,从而造成了时间浪费。我进行了如下两次对比实验,使用库函数swap和手写调换元素的函数进行对比,可以发现,使用swap函数的小数据拟合效果要明显好于手写。因此,小数据下,较差的拟合效果是因为较多次交换占用了更多时间,当数据较小时,数据交换造成的时间损耗更明显。但当数据变多时,这种影响被冲淡,故拟合效果比较好。


3. 插入排序


(1)算法实现原理

①假设前面n − 1(其中n ≥ 2 )个数已经有序的,现将第n个数插到前面有序序列中,并找到合适位置,使得插入第n 个数后仍为有序序列

②按照此法对所有元素进行插入,直至整个序列为有序序列


(2)源代码


INSERTION-SORT(A)
    for j=2 to A.length:
        key=A[j]
        //将A[j]插入已排序序列A[1..j-1]
        i=j-1
        while i>0 and A[i]>key
            A[i+1]= A[i]
            i=i-1
        A[i+1]=key

下面以使用插入排序3,5,1,2这四个数字为例,以图示介绍插入排序,见下图


e61ef10bb71f416fb2d35656d77bf6c7.png


(3)算法性能分析

①时间复杂度分析

在插入下标为i的元素的时候(假设该元素为x xx),R0,R1,R2,Ri-1

已经有序了,那么x 实际上有n + 1个备选位置可以插入,按照独立分布来说,每个位置的概率都是89b450b1602540f68d1c0cf63b8117f5.png,那么这n + 1 n+1n+1个位置从左到右对应的比较次数为( i , i , i − 1 , . . . , 1 )。那么我们就可以得到一趟插入排序的平均时间复杂度为

image.png

因此,插入排序的时间复杂度为O (n2)


②数据测试分析

使用随机数生成器生成了从102102  的不同数据量级的随机数,通过使用插入排序进排序并获取了程序运行时间。为降低偶然性,对20组数据取平均值,选  105时运行时间为理论值并做表如下:

cc94f33dd70b4398946f7b1c90096d1d.png


通过获得的数据,使用105 时的时间消耗为基准理论值,使用Tableau做图像并拟合如图:


eefe2d0861694e1c850941cd9b6b6b6a.png


由于插入排序算法时间复杂度为O ( n 2 ),故,数量级扩大10倍时,时间消耗应扩大100倍。由上图,可得随着数据量的增大,拟合效果越好,所有实验数据符合O ( n 2 ) 的时间复杂度。

从上表和上图中可以发现整体时间消耗都大致满足数量级扩大10倍,时间消耗扩大100倍的规律。但对于101102  数量级时存在较大误差,拟合效果较差。通过分析可知,插入排序中进行了对需插入元素的保存操作,当数据较小时,较差的拟合效果是因为每次对插入前数值的保存占用的时间比例较大。当数据较小时,数据交换造成的时间损耗更明显。但当数据变多时,这种影响被冲淡,故拟合效果比较好。


4. 快速排序


(1)算法实现原理

①首先设定一个分界值,通过该分界值将数组分成左右两部分。

②将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。

③然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

④重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。


下面以使用快速排序11,8,3,9,7,1,2,5这八个数字为例,以图示介绍快速排序,见下图


ad4c5987d66840b298423ac48643567c.png


(2)源代码


QUICKSORT(SeqList R,int low,int high)
  int pivotpos;//划分后的基准记录的位置
  if(low<high)
    //仅当区间长度大于1时才需排序
    pivotpos = Partition(R,low,high);
    //对R[low...high]进行划分
    QuickSort(R,low,pivotpos-1);
    QuickSort(R,pivotpos+1,high);


(3)算法性能分析

①时间复杂度分析:

快速排序的一次划分算法从两头交替搜索,直到low和high重合,因此其时间复杂度是O ( n ) ;而整个快速排序算法的时间复杂度与划分的趟数有关。

最理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log ⁡ n 趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O ( n log ⁡ n )

最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n nn的数据表的快速排序需要经过n nn趟划分,使得整个排序算法的时间复杂度为O ( n 2 )

综上快速排序的平均时间复杂度也是O ( n log ⁡ n )

②数据测试分析:

使用随机数生成器生成了从101106

的不同数据量级的随机数,通过使用快速排序进行排序并获取了程序运行时间。为降低偶然性,对20组数据取平均值,选择105时运行时间为理论值并做表如下


02020ce4dcd4418780ccce6caa7cf053.png

通过获得的数据,使用105 时的时间消耗为基准理论值,使用Tableau做图像并拟合如图



88d18833813b41fba72cf8d81da03cbb.png


结合上表和上图不难得出:整体时间消耗都大致满足O ( n log ⁡ n )的时间复杂度,且数据量越大拟合效果越好。

从上表和上图中可以发现整体时间消耗都大致满足时间复杂度。但对于101102,数量级时存在较大误差,拟合效果较差。通过分析可知,快速排序中开辟申请空间与递归栈都会影响运行性能和运行时间。当数据较小时,这种影响造成的时间损耗更明显。但当数据变多时,开辟空间与递归栈对时间的影响被冲淡,故拟合效果比较好。

相关文章
|
1天前
|
人工智能 自然语言处理 供应链
从第十批算法备案通过名单中分析算法的属地占比、行业及应用情况
2025年3月12日,国家网信办公布第十批深度合成算法通过名单,共395款。主要分布在广东、北京、上海、浙江等地,占比超80%,涵盖智能对话、图像生成、文本生成等多行业。典型应用包括医疗、教育、金融等领域,如觅健医疗内容生成算法、匠邦AI智能生成合成算法等。服务角色以面向用户为主,技术趋势为多模态融合与垂直领域专业化。
|
2天前
|
人工智能 自然语言处理 算法
从第九批深度合成备案通过公示名单分析算法备案属地、行业及应用领域占比
2024年12月20日,中央网信办公布第九批深度合成算法名单。分析显示,教育、智能对话、医疗健康和图像生成为核心应用领域。文本生成占比最高(57.56%),涵盖智能客服、法律咨询等;图像/视频生成次之(27.32%),应用于广告设计、影视制作等。北京、广东、浙江等地技术集中度高,多模态融合成未来重点。垂直行业如医疗、教育、金融加速引入AI,提升效率与用户体验。
|
13天前
|
存储 搜索推荐 算法
算法系列之排序算法-堆排序
堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。它的时间复杂度为 $O(nlogn)$,并且是一种原地排序算法(即不需要额外的存储空间)。堆排序的核心思想是利用堆的性质来维护一个最大堆或最小堆,然后逐步将堆顶元素(最大值或最小值)取出,放到数组的末尾,最终得到一个有序的数组。
28 8
算法系列之排序算法-堆排序
|
14天前
|
存储 缓存 监控
企业监控软件中 Go 语言哈希表算法的应用研究与分析
在数字化时代,企业监控软件对企业的稳定运营至关重要。哈希表(散列表)作为高效的数据结构,广泛应用于企业监控中,如设备状态管理、数据分类和缓存机制。Go 语言中的 map 实现了哈希表,能快速处理海量监控数据,确保实时准确反映设备状态,提升系统性能,助力企业实现智能化管理。
28 3
|
2月前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
3月前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
69 6
|
4月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
107 1
|
5月前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
5月前
|
算法
PID算法原理分析
【10月更文挑战第12天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
111 0
|
5月前
|
算法
PID算法原理分析及优化
【10月更文挑战第6天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
135 0