比较排序和线性时间排序

你的打赏是我奋笔疾书的动力!​


说线性时间时间排序,我们的大脑可能已经猜想出该类排序的时间复杂度是O(n),所以叫做线性时间排序,不错!你的大脑满满的都是逻辑。

然而,比较排序这个名词,你的大脑该如何灵光闪现呢?......

好吧。比较排序:在排序最终结果中,元素之间的次序依赖于他们之间的比较,故称归并排序,快速排序,堆排序,插入排序为比较排序。

比较排序可以抽象为一颗决策树。《算法导论》3个元素的决策树举例,1,2,3代表数组的下标,如下:

比较排序和线性时间排序_第1张图片

上图中可以看出,任何输入实例(例如:3!个输入实例)都可以在决策树(例如:含有3个元素)中找到一条从根节点到叶节点的路径对应起来,一条这样的路径就表示比较排序的一次实际执行过程。且数学归纳有n个元素决策树就有n!条这样的路径。

         且有上图可以看出,从根到叶节点的路径的长度表示比较排序中比较的次数,则决策树最长的路径表示比较排序中最坏情况的比较次数,也就是决策树的高度。

设有n个元素的决策树,树高是h,且已知,叶节点个数≥n!,则根据完全二叉树的叶节点个数的一些性质有决策树叶节点个数≤2^h,从而得出:

即:任何比较排序的算法在最坏情况下的比较次数要有Ω(n lg n)次比较。

 

非比较排序的线性时间排序的算法

计数排序:

该算法有一个前提条件:待排序的数据源的元素必须是整数

伪码如下:

比较排序和线性时间排序_第2张图片

这里直接举例说明伪码描述的算法过程。A[j]表述数据源,C[i](计数器)用来记录A[j]中各个数值出现的频率个数并且初始化为0,0<=A[j]<=k,j=0,1,…,n,B[]是输出排好序的数组

         2,3:A[] = {4,1,3,4,3},k=4,C[]={0,0,0,0},O(k)

         4,5:C[]={1,0,2,2},O(n)

         7,8:C[]={1,1,3,5}//总共有5个元素,小于等于4的有5个,小于等于3的有3个,小于等于2和1的分别有1个。O(k)

         10,11,12:O(n)

第一趟:j=5

         B[] = {0,0,3,0,0},C[]={1,1,2,5}

第二趟:j=4

         B[] = {0,0,3,0,4},C[]={1,1,2,4}

第三趟:j=3

         B[] = {0,3,3,0,4},C[]={1,1,1,4}

第四趟:j=2

         B[] = {1,3,3,0,4},C[]={0,1,1,4}

第五趟:j=1

         B[] = {1,3,3,4,4},C[]={0,1,1,3}

我们看到经过10,11,12这几步后输出排好序的数组为{1,3,3,4,4}。还可以得到计数排序

总的时间代价为O(k+n),在渐近意义下,要好于比较排序的O(n lg n)。比较排序的当k很大时,例如2^32大约是42亿,也就是要申请42亿个int的空间即16G,土豪的笔记本绝对可以这样漂亮的干仗!所以不是土豪的话,我们只能改进算法,基数排序登场。

         稳定排序(Stable sort):计数排序的一个重要性质。相同值的元素在输出数组中的相对次序与在输入数组中的相对次序一致,即:相同值的两个元素,在输入数组中先出现的数在输出数组中也先出现。这个性质对携带有附加数据的元素很重要。

基数排序:

假设有n个d位的整数存在于数组A中,则伪码描述该算法有:

         举例如下:

比较排序和线性时间排序_第3张图片

         算法理解起来是简单,但是它的时间复杂度真的是线性的吗?下面分析一下时间复杂度相关的问题,分析如下:

1.对数组中每一位数字的每一位使用计数排序(渐进意义下运行时间最小的排序算法),因此它的时间复杂度是O(dn+k),d是数字的位数。

2.假设n个整数,每个整数用二进制表示,且有b个比特,则,数组中元素的取值范围是0~2^b-1

3.把连续的比特看作一位,这样可以用计数排序一次处理最多比特。所以把每个整数划分成b/r位数(b/r轮计数排序);每一位数有r个比特位,且每一位取值范围是0~2^r-1(2^r就是计数排序中的k)。

4.由3可以估得运行时间:,为使得运行时间复杂度变小,在设b和n为常值的情况下,我们可以选择适当的r取值。对r求导数等于0 的解,其精确解为: .是关于n的一个递增函数式,可以看出待排序的整数越多,划分比特位数r也越多,当待排序的整数个数n足够大时(由r<=b决定足够大的n),r只能取到上限b,进而时间复杂度变为O(n+2^b),若b<=lgn时,时间复杂度变为O(n)。

5.我们先不管精确解,其中,而中r越大越小,且r<=b;中r越小越小。一项要求r大一点好,另一项要求r小一点好,我们不妨分别假设下的情况,若,则r<=lg n;反之则r>=lg n。若,则r最大取值lg n,则,若b<=lgn就是4中的列出情况;反之则r>=lg n,此时在r趋于无穷时是无穷大量,却可以得到下界……….

排序算法中按照时间复杂度在渐进意义上的排序,基数排序是最优的排序算法,但是它有一个限制,关键字必须是整数,然而,很多排序问题都是化成关键字为整数的情况来排序的。

是不是基数排序比比较排序更优秀呢?前面讲过,时间复杂度只是当n值趋于无穷时的在渐近意义下的运行时间,可别忘了隐匿在复杂度里的常数因子。

是不是基数排序O(n)在渐进意义上是最优的排序算法呢?你回答若是肯定的话,那你可能是忘了中国的古话“一山还比一山高”,“长江后浪推前浪,一浪更比一浪高”。看过算法导论的学生可能了解过MIT的一位计算机科学家提到过一个随机算法,对于一个字长的整数排序,目前已知的最好的排序算法的期望运行时间是O(nlglgn),他还指出:有很多非常复杂的算法,但是它们可以给我们某种信息,你可以打破对b的依赖,只要你知道b最多是一个字长。由此归纳可知科学的高峰只要你愿意攀登,总是有惊奇出现,你的半亩三分地有时候真的是不值得一提。

你的打赏是我奋笔疾书的动力!

支付宝打赏:

微信打赏:

你可能感兴趣的:(算法)