#排序算法整理#

冒泡排序:

冒泡排序算法的思想是:如果一个数组中相邻的元素对都是不降序的,那么这个数组也是不降序的,我们可以利用归纳法或者反证法证明。那么,只要我们不断改善局部的有序性,最后就一定可以得到有序的数组。我们通过遍历数组,查看相邻元素是否有序,如果无序则交换它们,来改善局部有序性。可见,第一次遍历会使当前最大的元素就位,第二次遍历则可以不考虑已就位的元素,会使当前第二大的元素就位,以此类推,经过n-1遍历会使n-1个元素就位,最后一个元素也自然而然就位。n个元素中存在n-1个相邻对。那么第一次遍历的扫描数为n-1,最后一次是,已经有n-2个元素就位的情况,也就是只有2个元素剩余,扫描数为1,算法的时间复杂度就是,1+2+3….+n-1次 *常数时间 + 常数时间 = O(n^2).

归并排序

归并排序算法是一个递归算法,它的描述如下,将数组划分为两个子数组,对它们递归的进行归并排序,然后合并排序好的子数组,即可以得到有序的数组。由这个描述我们可以知道,算法包括两个部分,划分和归并。当子数组的元素只有1个的时候,子数组当然有序,停止继续递归,这就是递归基。利用一个辅助函数merge归并两个有序的子数组。

merge的时间复杂度,即是就位n个元素的时间,每次就位需要常数时间,所以复杂度为O(n)

依据描述,不难得到归并算法的实现:

递归基->划分->递归归并->划分->递归归并->合并有序的子数组
算法的时间复杂度:假设排序一个规模为n的数组所需的时间为T(N)
那么可以得到递推式子:T(N) = T(N/2) + T(N/2) + O(n)
通过绘制递归图可以得到:T(N) = T(1)N + O(N) logn = O(nlogn);
其实,O(nlogn)已经是一般排序算法的最优时间复杂度了。

快速排序:

快速排序算法是递归算法,它的描述如下,选择一个元素作为主元,将数组划分为两部分,第一部分的元素值都小于等于主元,第二部分的元素值都大于主元。对于这两部分,分别递归的应用快速排序算法。
当子数组的元素数目为1时,子数组已经有序,结束继续递归,此为递归基。算法的主要部分在于划分。我们选择当前数组的第一个元素作为主元,然后划分数组。划分数组的算法如下:

确定数组的第一个元素为主元,然后从第二个元素起开始寻找第一个大于主元的元素,从最后一个元素起寻找第一个小于等于主元的元素,
如果这两个元素是不同的元素,则交换它们。当前后重叠后,则说明,除当前元素之前的所有元素都小于等于主元,之后的所有元素都大于主元。如果当前元素大于主元,则将high往前移动一位,则high就是主元的位置,交换high和first的值,返回主元的位置,完成分割。
算法的复杂度,算法最多进行N次比较和小于N次的交换再加上常数时间的一般操作,则时间复杂度为0(n).
快速排序算法实现:根据递归描述,不难得到算法的实现:

划分->递归排序前半部->递归排序后半部
算法的时间复杂度,最坏的情况下,每一次划分都得到一个长度为0和一个长度为n-1的数组,那么时间复杂度为n + n-1 + …1 为O(n^2)
一般情况下,每一次划分平均划分为两个长度相等的子数组,那么可以得到递推式 T(N) = T(N/2) +T(N/2) +O(N) 根据和归并排序相同的方法,可以求得时间复杂度为O(logn*n).快速排序算法不需要额外的空间,所以空间复杂度较归并排序低。但是最坏情况下的时间复杂度较归并高。

堆排序

堆排序是一种利用了堆数据结构的排序算法。我们首先讨论堆这种数据结构,理解了堆也就理解了堆排序。堆是一颗完全二叉树,而且它的父节点值不小于它的任意孩子节点值。完全二叉树是一颗二叉树,它除了最后一层,其它层的节点都是满的,而且最后一层的节点是偏左放置的。基于这个特性我们可以利用一个线性表来存储完全二叉树,根据归纳不难发现,对于位置i的节点它的左孩子位于2i+ 1,右孩子位于 2I + 2 ,它的父节点位于 (i-1)/2 .为了维持堆的性质,需要相应的特化的添加和删除节点算法。以下分别讲解。
添加节点的算法,描述如下:将节点加入线性表的末尾,成为堆的一个叶子,判断当前节点的值是否大于父节点的值,如果是交换它与父节点,更新当前节点的位置,如此循环,直到,当前节点为根节点,或者当前节点的值不再大于父节点的值。实现如下:

删除节点的算法描述如下:堆只允许删除根节点,将线性表的第一个值更新为最后一个节点的值,删除最后一个节点,令根节点为当前节点,判断当前节点是否小于它的较大子节点,如果是,交换它与较大的子节点,更新当前节点,直到,当前节点大于或等于它的较大子节点,或者,当前节点没有子节点为止。实现如下:

有了堆结构后,排序算法仅仅是将数组放入堆中,然后依次删除即可。
算法的复杂度分析:对于长度为N的数组,算法需要N次插入堆和N次删除跟节点的操作。对于长度为N的堆,删除和插入一个节点需要最多遍历树高次即logN,则算法的时间复杂度为O(N*logN).

桶排序

一般排序算法的最优时间复杂度是O(logN*N),但是当数据量较小时可以采用不一般的排序算法,使时间复杂度优化到O(N)。桶排序算法的思想是,对于一个数组,遍历它将每一个元素依次放入对应的桶中,遍历结束后,将桶中的元素倒回数组中,即可以得到有序的数组。桶的数组的元素的键值数目。
算法实现如下:

算法的时间复杂度分析:第一个循环时间为 数组大小n * 常数 ,第二个循环时间为 桶数目大小N * 常数, 可见时间复杂度是O(N)。

基数排序

基数排序类似于桶排序,只不过,它经过了多次桶排序,对于一个正整数(负整数另做考虑),从低位到高位分别对应第一个基数和第d个基数。按照基数大小进行d次桶排序即可得到排好序的数组。我们先考虑如何得到一个整数的第m个基数,根据数学知识知道,第一个基数为val % 10 ,第二个基数为 val/10%10,依次类推,那么可以得到获得整数第m个基数的算法。

剩余的实现,仅仅是桶排序的一点小扩展:

算法的时间复杂度,前面已经说过,基数排序相当于进行了基数的数目个桶排序,所以时间复杂度为O(dn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值