排序算法

排序可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,外部排序是因为排序的数据量很大,一次不能容纳全部的排序记录,在排序过程中需要访问外部存储空间。

内存中排序算法介绍。

冒泡排序

思想:通过与相邻元素的比较和交换把最小的数交换到最前面,从后向前遍历(或者把最大的数交换到最后面,从前到后遍历)。平均和最差的时间复杂度O(n^2)。空间复杂度O(1)。稳定的算法。如果算法优化,最好的时间复杂度为O(n).

插入排序

平均和最坏时间复杂度O(n^2),空间复杂度O(1)。最好时间复杂度O(n)。

选择排序

最好最坏和平均的时间复杂度O(n^2),空间复杂度O(1).排序时间与输入无关。不稳定。

归并排序

时间复杂度O(nlogn),空间复杂度O(n)+O(logn).排序时间与输入无关。稳定。通过递归分解数列,然后合并数列。由于归并排序在归并过程中需要与原始记录序列同样数量的存储空间存放归并结果 以及 递归时深度为 log_2n 的栈空间,因此空间复杂度为O(n+logn)

另外,对代码进行仔细研究,发现 Merge 函数中有if (L[i]<R[j]) 语句,这就说明它需要两两比较,不存在跳跃,因此归并排序是一种稳定的排序算法。

也就是说,归并排序是一种比较占用内存,但却效率高且稳定的算法。

堆排序

时间复杂度 O(nlogn), 空间复杂度O(1). 从这一点就可以看出,堆排序在时间上类似归并,但是它又是一种原地排序,时间复杂度小于归并的O(n+logn)
排序时间与输入无关,最好,最差,平均都是O(nlogn). 不稳定

对于大数据的处理: 如果对100亿条数据选择Topk数据,选择快速排序好还是堆排序好? 答案是只能用堆排序。 堆排序只需要维护一个k大小的空间,即在内存开辟k大小的空间。

快速排序

时间复杂度 O(nlogn) 空间复杂度O(logn) 不稳定 。最坏O(n^2) 当划分不均匀时候 逆序and排好序都是最坏情况
最好O(n) 当划分均匀partition的时间复杂度: O(n)一共需要lognpartition。空间复杂度:递归造成的栈空间的使用,最好情况,递归树的深度logn 空间复杂的logn,最坏情况,需要进行n‐1 递归调用,其空间复杂度为 O(n),平均情况,空间复杂度也为O(log2n)

由于关键字的比较和交换是跳跃进行的,因此,快速排序是一种不稳定的排序方法。

快速排序的每一轮就是将这一轮的基准数归位,直到所有的数都归为为止,排序结束。 快速排序之所比较快,因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是 O(n^2),它的平均时间复杂度为 O(nlogn)。其实快速排序是基于 “二分” 的思想。

计数排序

在排序的时候就知道他的位置,那不就是扫描一遍,把他放入他应该的位置不就可以了。 要知道他的位置,我们只需要知道有多少不大于他不就可以了吗?

最好,最坏,平均的时间复杂度O(n+k)

优点:不需要比较函数,利用地址偏移,对范围固定在[0,k]的整数排序的最佳选择。是排序字节串最快的排序算法。

缺点:由于用来计数的数组的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。

请给出一个算法,使之对给定的介于 0到 k 之间的 n个整数进行预处理,并能在O(1) 时间内回答出输入的整数中有多少个落在 [a...b] 区间内。你给出的算法的预处理时间为O(n+k)

分析:就是用计数排序中的预处理方法,获得数组 C[0...k],使得C[i]为不大于 i的元素的个数。这样落入 [a...b] 区间内的元素个数有 C[b]-C[a-1]

基数排序

假设我们有一些二元组(a,b),要对它们进行以a 为首要关键字,b的次要关键字的排序。我们可以先把它们先按照首要关键字排序,分成首要关键字相同的若干堆。然后,在按照次要关键值分别对每一堆进行单独排序。最后再把这些堆串连到一起,使首要关键字较小的一堆排在上面。按这种方式的基数排序称为 MSD(Most Significant Dight) 排序

第二种方式是从最低有效关键字开始排序,称为 LSD(Least Significant Dight)排序 。首先对所有的数据按照次要关键字排序,然后对所有的数据按照首要关键字排序。要注意的是,使用的排序算法必须是稳定的,否则就会取消前一次排序的结果。由于不需要分堆对每堆单独排序,LSD 方法往往比 MSD 简单而开销小。

时间复杂度O(n)

桶排序

桶排序假设待排序的一组数均匀独立的分布在一个范围中,并将这一范围划分成几个子范围(桶)。

然后基于某种映射函数f ,将待排序列的关键字 k 映射到第i个桶中 (即桶数组B 的下标i) ,那么该关键字k 就作为 B[i]中的元素 (每个桶B[i]都是一组大小为N/M 的序列 )。

接着将各个桶中的数据有序的合并起来 : 对每个桶B[i] 中的所有元素进行比较排序 (可以使用快排)。然后依次枚举输出 B[0]....B[M] 中的全部内容即是一个有序序列。

平均时间复杂度为线性的 O(n+C) 最优情形下,桶排序的时间复杂度为O(n)
桶排序的空间复杂度通常是比较高的,额外开销为O(n+m)(因为要维护 M 个数组的引用)。
就是桶越多,时间效率就越高,而桶越多,空间却就越大,由此可见时间和空间是一个矛盾的两个方面。

算法稳定性 : 桶排序的稳定性依赖于桶内排序。如果我们使用了快排,显然,算法是不稳定的。

 

参考:

[1] https://segmentfault.com/a/1190000002595152

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值