目录
一、没什么大用的逼逼叨
(一).排序算法应用
(二).排序算法的分类
二.如何认识和评价一个排序算法
(一)时间复杂度
(二)空间复杂度
(三)平均性能
(四)稳定性
(五)对不同数据类型的适应性
三.算法机制和实现
(一)准备工作&说明
(二)BubbleSort(冒泡排序)
(三)Insertion(插入排序)
(四)SelectionSort(选择排序)
(五)ShellSort(希尔排序)
(六)MergeSort(归并排序)
(七)QuickSort(快速排序)
(八)TestSort(测试方法)
1.测试数组的生成
2.计时器编写
四.总结
一、没什么大用的逼逼叨
下面看点相关知识热身
(一).排序算法应用
- 数据组织:排序算法可以将数据按照特定的顺序进行排列,使其更易于组织和管理。有序的数据结构可以提高数据的查找、插入和删除操作的效率。
-
搜索和查找:排序后的数据可以采用更高效的搜索和查找算法进行操作。
-
数据分析和统计:排序算法可以帮助对数据进行分析和统计。例如,对一组无序的数字进行排序后,可以更方便地计算中位数、众数、范围等统计指标。
-
数据压缩和编码:某些压缩算法和编码技术要求数据按照一定的顺序进行排列。排序算法可以满足这些需求,使得数据在进行压缩或编码时更加高效。
-
数据展示和可视化:排序后的数据可以更直观地展示和可视化。例如,在图表或图形中展示排序后的数据,可以更清晰地观察数据的分布。
感觉我在水文章。。。。。
(二).排序算法的分类
排序按照移动方式可分为直接移动和逻辑移动两种方式。直接移动是直接交换存储数据的位置(在前期阶段的学习中更加常见),而逻辑移动并不会移动数据存储的位置,仅改变指向这些数据辅助指针的值。这里对逻辑移动做一个简单展开,便于各位理解
链表结构:当排序的数据以链表的形式存储时,直接交换节点的位置可能会导致时间复杂度较高。此时,通过逻辑移动,即改变节点之间的指针关系,可以更高效地进行排序操作。
大规模数据:对于大规模数据集合,直接交换元素的位置可能会涉及较多的数据搬移操作,导致性能下降。在这种情况下,通过逻辑移动,即通过修改辅助指针的值,可以避免大规模的数据移动,提高排序效率。
硬件限制:在某些硬件环境下,直接交换数据的位置可能会引入较高的开销。例如,使用磁盘进行排序时,读取和写入数据的成本较高,直接移动数据可能会导致较多的磁盘操作。使用逻辑移动,可以减少实际的数据移动操作,从而提高排序的效率。
排序按照实现过程分为内部排序和外部排序。数据量小时,所有的数据均可以全部加载到内存进行排序,这种排序称为内部排序;数据量过大而无法一次性加载到内存中,则需要借助硬件(磁带,磁盘等)辅助存储器进行排序的,则称为外部排序。
请各部门进入学习状态,下面正式开始
请各部门进入学习状态,下面正式开始
请各部门进入学习状态,下面正式开始
二.如何认识和评价一个排序算法
(一)时间复杂度
时间复杂度是衡量算法执行时间随输入规模增长而增长的量度。它描述了算法执行所需的时间与输入规模之间的关系。
在算法评估中,时间复杂度用于比较不同算法的效率。具有较低时间复杂度的算法意味着它在处理大规模问题时所需的时间较少。通过比较算法的时间复杂度,可以选择最优的算法来解决特定的问题。
此外,时间复杂度还有助于预测算法在实际应用中的执行时间,可以提供一个相对的参考,帮助我们估计算法的可行性和可接受性。
时间复杂度只考虑算法执行时间与问题规模之间的关系,不考虑具体的硬件环境、编程语言等因素。
//想要得到更详细的知识可点击链接,水平不够就不多bb了
(二)空间复杂度
空间复杂度是衡量算法所需的额外空间随输入规模增长而增长的量度。它描述了算法所使用的额外空间与输入规模之间的关系。
额外空间和输入空间:空间复杂度通常指的是算法所需的额外空间,即除了输入数据本身所占用的空间外,算法执行过程中额外使用的空间。输入空间是指算法所接受的输入数据的空间占用。在分析空间复杂度时,通常将额外空间与输入空间区分开来。
原地算法(In-place Algorithm):原地算法是指一种空间复杂度为常数的算法,它可以在有限的额外空间下完成操作,而不需要使用与输入规模成比例的额外空间。原地算法对于内存受限的环境或大规模数据的处理非常有用。
空间优化:通过重新设计数据结构、减少临时变量的使用、使用迭代代替递归等技巧,可以对算法进行空间优化,以减少额外空间的使用。
空间复杂度分析方法:空间复杂度可以使用数据结构、辅助空间和递归深度等来推导。常见的计算方法包括使用大O表示法、计算递归调用所需的栈空间、分析递推关系式等。
例如:冒泡排序、插入排序、选择排序、希尔排序和快速排序都是原地排序算法,它们的空间复杂度都是O(1),不需要额外的空间。而递归排序的空间复杂度取决于递归调用的深度,最坏情况下的空间复杂度为O(n),这就是所谓的空间换时间。
(三)平均性能
在设计算法时,我们也需要考虑空间复杂度和时间复杂度之间通常存在权衡关系,有时可以通过增加额外空间来减少时间复杂度,或者通过减少额外空间来增加时间复杂度,在选择算法时,需要根据具体问题和需求来平衡空间和时间的利用。
我们先针对本文的情况进行分析,想要更加客观的评判排序算法的平均性能,除了通过暴力美学进行数学计算,我们还可以采用代入一些特殊的数组进行模拟排序,记录空间和时间复杂度,通常特殊数组的设计采取下面这几种思路
//生成一个长度为N的完全逆序数组,用来表示排序面临的最差情况,估测算法的O( ),这只是一个通用的方法,针对不同的排序方法,最差情况不一定是如此
//生成一个长度为N的正序的数据序列,针对算法
设计的数组,表示最优情况。相对而言参考价值不高,适用于需要对结果进行多次check的实例。
//随机生成数组,估测算法的
//针对一些特殊情况我们还可以用撒点法针对性生成符合正态分布,有大量重复元素的数组等
(在后面将会进行简答的代码演示)(八)TestSort(测试方法)
下面是关于估算平均状态下算法性能的一些理论知识和习题
输入分布:算法的平均情况下的性能取决于输入数据的分布情况。不同的输入分布可能导致不同的执行路径和性能表现。常见的输入分布包括均匀分布、正态分布、随机分布等。根据实际应用场景和数据特点,选择适当的输入分布模型是分析算法平均性能的关键。
注意!在除了更换排序算法,我们还可以通过数据处理改变输入数据的分布情况,不过这更多牵扯到机器学习的内容。概率分析:通过概率论和统计学的方法来分析算法在平均情况下的性能。它涉及到计算各种输入情况下的概率,并将这些概率与算法的执行时间或空间利用进行加权平均。这样可以得到算法的平均性能估计。
期望值:期望值是概率分析中常用的概念,表示随机变量的平均值。对于算法的平均性能分析,可以计算算法在各种输入情况下的性能,通过加权平均数计算。
随机化算法:随机化算法是一种利用随机性来提供更好平均性能的算法。通过引入随机性,随机化算法可以减少最坏情况出现的可能性,并在平均情况下提供更好的性能。常见的随机化算法包括快速排序的随机化版本(会更新)和随机选择算法等。
(四)稳定性
排序的稳定性指的是保证排序前2个相等的数其在序列的前后位置顺序在排序后不变。
如数组arr[6]={5 , 3 , 4 , 2(1) , 2(2) , 3}其中有两个相等的元素2,我们给他编号为2(1)和2(2),没有开始排序时,2(1)在2(2)之前。如果排序算法在排序后,有可能使得2(1)和2(2)前后关系发生改变,则这个算法不具有稳定性。
在某些情况下,需要对对象的多个属性进行排序,其中某些属性具有相等的值。如果排序算法是稳定的,那么在对其中一个属性进行排序的同时,可以保持其他属性的相对顺序不变。简单来说,比如淘宝里多重检索,价格+评价双排序,查询论文年限和关键词双排序。
(五)对不同数据类型的适应性
在应用中的排序不仅仅局限于整数、浮点数类型的数据,很多时候还需要对字符串甚至图片等其他类型进行排序。递归排序通常是基于比较的排序算法,适用于各种类型的可比较数据。可以通过自定义比较函数来处理自定义数据类型。
如果不考虑效率,其实我们只需要针对每一种数据类型设计一个判定“大小”的函数,就可以实现排序算法的移植了
三.算法机制和实现
(一)准备工作&说明
为了增强代码的可读性和复用性,我们选择先编写了一个抽象类,其中less()用于在比较时替换掉让人眼花缭乱的大于小于号,exchange()则将交换封装起来
show(),isSorted(),sort()则更多是一个承上启下的作用,为操作者提供了一些简单的功能方便对后续的性能测试和检验。
同时,在分析算法性能时我们采用了不同的乱序数组,希望提前了解的可以先看(测试),不影响食用。
ps:这里我们均采用直接移动的方式。当然如果我们希望这个抽象类进一步兼容逻辑移动,可以选择给exchange()一个Comsumer<Comparable>参数,或者在此基础上编写两个抽象子类进一步划分
代码速览
exchange(a[] ,b,c) a数组中序号为b和c交换
less(a,b) 表示
a
小于b
,方法返回true,
反之为falseshow(a[ ]) 20个一行打印
isSorted(a[ ]) 检查a[ ]是否已经排序完成
sort() 抽象方法
源代码附上
public abstract class SortAlgorithm { public abstract void sort(Comparable[] objs); protected void exchange(Comparable[] numbers, int i, int j){ Comparable temp; temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; } protected boolean less(Comparable one, Comparable other){ return one.compareTo(other) < 0; } protected void show(Comparable[] numbers){ int N = numbers.length; int line = 0; for(int i = 0; i < N; i++){ System.out.printf("%s ", numbers[i]); line