排序算法

来源:互联网 发布:mac怎么下载2个qq 编辑:程序博客网 时间:2024/05/21 11:58

排序算法

排序算法有好多,比如冒泡排序、插入排序、归并排序、堆排序、快速排序、希尔排序、计数排序、桶排序等等,下面我对各种排序的原理和优缺点进行介绍。

  • 冒泡排序

冒泡排序是排序算法中最简单的,其原理是每次遍历所有没有排好序的元素一遍,找到最大值(最小值),将无序的第一个元素和最大值交换,原理如下:
分析冒泡排序的时间复杂度:

  • 插入排序

插入排序由名字就可以知道,就是将无序的序列一个一个插入到有序的序列中。其原理和拿牌差不多,我们拿牌的时候是一张一张从牌低拿到手里面的,我清牌的原理是每拿到一张牌,我就将其放到其当前正确有序的位置,当牌拿完了,手里的牌就清好了。不懂的话你再想想你打牌时候怎么清牌,大部分人都采用这种方法。下面来看其具体的过程。


由上可知,当插入元素和排好序的元素相等时,将插入元素放到该元素的后面,所以插入排序是稳定的。下面计算一下插入排序的时间复杂度,时间复杂度的计算都是最坏情况下的时间复杂度,当初始元素序列是按照逆序排列的,这时候所需要的时间复杂度最高为


  • 并归排序

并归排序其原理是将一个无序的序列分成若干组,然后将该若干组在组内排好序后,组间进行合并,合并后的组依然是排好序的,当将所有的小组都合并完后,合并后的序列就排好序了。打个比喻,假如你们学院要打一场篮球赛,怎么才能比较快的打完这场篮球赛并且把名次给分出来呢??不用说肯定是先把所有队伍分成若干个小组,打小组赛,然后层层晋级最后把得到名次,并归排序的原理就是这样。下面来看并归排序的具体过程:


该过程只要分为三个部分:分解,排序,合并。通过这三步我们来分析并归排序的时间复杂度:因为合并操作需要的时间,所以递归表达式如下:
通过主方法可以得到并归排序的时间复杂度为

  • 堆排序

堆排序是建立在堆的概念上的,可以看做是一棵完全二叉树。最大堆的性质是所有的父节点的值都大于该节点,同样最小堆的性质是所有父节点的值都小于该节点。利用最大堆和最小堆可以对无序的数进行两种方式的排序。

对于堆排序的原理,本质上最小堆和最大堆是一种数据结构,由于其特殊性,所以用来排序。简单来说,由最小堆的性质可以知道,堆的根节点必然是所有元素的最小值,所以可以将该元素取出,放入数组中(这里仅仅理解成放入另外数组,实质上该元素还在堆内),取出后需要对最小堆的性质进行维护,维护后的最小堆的根节点还是当前所有元素的最小值,重复上述操作,1.取最小值2.维护堆性质,最后数组中的数据就按照从小到大排序好了。下面来看看具体的过程:
上图中是按照最大堆从大到小排序,将根节点一个一个取出,而后在维护堆的性质。因为每次维护堆的性质需要的时间,有n个元素需要取出,所以堆排序的时间复杂度为

  • 快速排序

在所有的排序算法中,快速排序用的是最多的,c++里面sort排序的算法用的就是快排。快排有点有好多,比如平均性能好,换句话说就是平均复杂度其他算法要好,但是缺点是不稳定。不稳定的意思就是该算法对于一些序列时间复杂度非常低,但是有些序列时间复杂度和冒泡差不多。下面介绍一下快速排序的过程:简单的说就是,取无序序列中一个元素作为关键字,然后利用该关键字将所有元素分成两个小组,左边的元素都比关键字小,右边元素都比关键字大(一般而言我们去第一个元素作为关键字)。而后将左边小组和右边小组重复上述操作,当小组中只有两个元素时,结束排序。具体过程如下:

分析可以知道,快速排序的递归式如下:


通过该递归式可知,该算法的最坏时间复杂度为,但是这并不影响该算法的平均性能,期望运行时间为

  • 希尔排序

希尔排序的原理也是采用分组,只不过分组的形式不同而已。具体是选择一个步距d,按照这个步距将无序元素分成若干组。假设d=4,则1,5,9.。。等元素为一组;2,6,10.。。等元素为一组,依次类推。当然进行下一次排序的时候就需要对d的值进行改变,d=d/2,直到d=1时完成排序。过程如下:


可以看出该算法排序的时间复杂度和d的取值有关,但是目前没有选取最好d的方法。所以该方法是十分不稳定的,时间复杂度可能很好,也可能很差。

  • 计数排序

计数排序是一个很神奇的排序算法,之所以说它神奇,是因为你不知道它为什么可以,但是就是排好序了,而且效果还很不错。通过本质看现象,有书上说计数排序是一种线性的排序算法,我觉得这有些误导,其本质不是线性的,该算法时间复杂度为,u代表最大值与最小值之间的范围,不是元素的个数,所以我说该算法不是线性的,而且该算法是牺牲了空间复杂度来换取时间复杂度的,所以桶排序适合于元素比较密集的时候使用,不然还不一定有冒泡排序性价比高。由于计数排序的原理实在神奇,下面聊聊它的具体过程吧:

假设排序序列为4、1、3、4、3,存入数组中,则有:


由数组A可以得到数组C:


C数组中的值为A中元素出现的次数,C1'数组表示前n个数的和:



当n=5时,A[5]=3,C1'[3]=3,所以B[3]=3:

同时更新C1'的数据,相应位减1:


当n=4时,A[4]=4,C1'[4]=4,所以B[4]=5:



直到n=1时,得到排序后的数组B:

计数排序过程如上,看完整个过程我也是一脸懵逼的,但是人家确实实现排序了,时间复杂度也很好。所以原理就不讲了,知道过程就行。


  • 桶排序

桶排序的原理是啥??简单来说,该算法就是普通排序和分组的融合出来的一个算法。假设由100个数,这100个数的范围是0~1000,则可以产生100个区间,相当于100个桶,每个区间是10,然后将100个数分别放在桶里,然后分布在桶里面的元素可以通过快速排序来对其进行排序,最后合并就可以得到排好序的序列。

就是这样简单。

  • 分析


稳定性

排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录,经过排序, 这些记录的相对次序保持不变,则称该算法是稳定的;若经排序后,记录的相对 次序发生了改变,则称该算法是不稳定的。 

 稳定性的好处:排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。另外,如果排序算法稳定,可以避免多余的比较。

稳定的排序算法冒泡排序、插入排序、归并排序和基数排序

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序


总结

一般情况下,排序算法需要根据实际情况选择,如果数据量不大,我们可以选择插入或者并归排序,数据量较大时,我们选择快速排序、堆排序。桶排序主要在数据均匀分布的情况下,计数排序用于数据比较密集的情况下。
原创粉丝点击