排序(一)

最经典,最常用的排序算法:
冒泡排序,插入排序,选择排序,归并排序,快速排序,计数排序,基数排序,桶排序。
按照时间复杂度把它们分成了三类:
排序算法            时间复杂度        是否基于比较
冒泡,插入,选择    O(n^2)            是
快排,归并            O(nlogn)        是
桶,计数,基数        O(n)            不是

如何分析一个“排序算法”?
学习排序算法,我们除了学习它的算法原理,代码实现之外,更重要的是要学会如何评价,分析一个排序算法。那分析一个排序算法,要从哪几个方面入手呢?

1.排序算法的执行效率?
对于排序算法执行效率的分析,我们一般会从这几个方面来衡量:

(1)最好情况,最坏情况,平均情况的时间复杂度
我们在分析排序算法的时间复杂度时,要分别给出最好情况,最坏情况,平均情况下的时间复杂度。除此之外,你还要说出最好,最坏时间复杂度对应的要排序的原始数据是什么样的。
为什么要区分这三种时间复杂度呢?第一,有些排序算法会区分,为了好对比,所以我们最好都做一下区分。第二,对于要排序的数据,有的接近有序,有的完全无序。有序度不同的数据,对于排序的执行时间肯定是有影响的,所以我们要知道排序算法在不同数据下的性能表现。
    
(2)时间复杂度的系数,常数,低阶
我们知道,时间复杂度反映的是数据规模n很大的时候的一个增长趋势,所以它表示的时候会忽略系数,常数,低阶。但是实际的软件开发中,我们排序的可能是10个,100个,1000个这样规模很小的数据,所以,在对同一阶的时间复杂度的排序算法性能对比的时候,我们就要把系数,常数,低阶也考虑进来。

(3)比较次数和交换(或移动)次数
对于基于比较的排序算法,在执行过程中,会涉及两种操作,一种是元素比较大小,另一种是元素交换或移动。所以,如果我们在分析排序算法的执行效率的时候,应该把比较次数和交换(或移动)次数也考虑进去。

2.排序算法的内存消耗:
算法的内存消耗可以通过空间复杂度来衡量,排序算法也不例外。不过,针对排序算法的空间复杂度,我们还引入了一个新的概念,原地排序(Sorted in place)。原地排序算法,就是特指空间复杂度是O(1)的排序算法。冒泡,插入,选择排序,都是原地排序算法。

3.排序算法的稳定性:
仅仅用执行效率和内存消耗来衡量排序算法的好坏是不够的。针对排序算法,我们还有一个重要的度量指标,稳定性。这个概念是说,如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。

可能会问,既然都是相同的,哪个在前,哪个在后,又有什么关系呢?但是在真正软件开发中,我们要排序的往往不是单纯的整数,而是一组对象,我们需要按照对象的某个key来排序。

比如说,我们现在要给电商交易平台交易系统中的“订单”排序。订单有两个属性,一个是下单时间,另一个是订单金额。如果我们现在有10万条订单数据,我们希望按照金额从小到大对订单数据排序,对于金额相同的订单,我们希望按照下单时间从早到晚有序。对于这样一个排序需求,我们怎么来做呢?

最先想到的方法是:我们先按照金额对订单数据进行排序,然后,再遍历排序之后的订单数据,对于每个金额相同的小区间再按照下单时间排序。这种排序思路理解起来不难,但是实现起来会很复杂。

借助稳定排序算法,这个问题可以非常简洁地解决。解决思路是这样的:我们先按照下单时间给订单排序,注意是按照下单时间,,不是金额。排序完成之后,我们用稳定排序算法,按照订单金额重新排序。两遍排序之后,我们得到的订单数据就是按照金额从小到大排序,金额相同的订单按照下单时间从早到晚排序的。为什么呢?

稳定排序算法可以保持金额相同的两个对象,在排序之后的前后顺序不变。第一次排序之后,所有的订单按照下单时间从早到晚有序了。在第二次排序中,我们用的是稳定的排序算法,所以经过第二次排序之后,相同金额的订单仍然保持下单时间从早到晚有序。

猜你喜欢

转载自blog.csdn.net/zpwggi123/article/details/83057840