排序

下图是对常见的几种排序的简单分类:
在这里插入图片描述

时间复杂度、空间复杂度以及稳定性
插入排序:

1、直接插入排序:
是将一个数根据它的大小插入到一个已经有序的数组中,从而得到一个个数加一的新的有序数据,该算法适用于少量数据的排序,时间复杂度为O(n^2),是一种稳定的排序方法。

思想(配合示意图食用更佳):
从第二项开始遍历整个数组,当a[i]<a[i-1]时,把a[i]的值保存到tmp;
从a[i]开始,逐个往前遍历,当tmp的值小于a[i-1]时,记下此时的位置为a[j],把a[j]赋给a[i],然后 j-- 继续向前;当tmp的值大于a[j]时,跳出循环;
把之前tmp保存的值赋到最后跳出循环的位置。

示意图:
在这里插入图片描述

时间复杂度分析:首先要遍历数组找到tmp,这是一个O(n);找到tmp之后,向前遍历找到插入的位置,也是O(n);所以插入排序的时间复杂度为O(n^2)。

2、希尔排序
希尔排序是进阶版的插入排序,它是将整个数组分为几个小数组,每个小数组先进行排序,再对这些有序的小数组排序,最后原始数组就会成为一个有序的数组。

思想:

  • 大数组划分为小数组是希尔排序与插入排序最大的区别,正因为如此,希尔排序的效率才有所提高。
  • 划分数组的依据是gap的大小,gap的初始值我们将它设置为数组的大小,后续gap的取值为gap/3+1(大牛们总结的,这样的效率是最高的),当gap的值为1时,就变成了普通的插入排序。
  • 分组完成后的排序方法和插入排序是一致的。
    在这里插入图片描述
    在这里插入图片描述
选择排序

1、选择排序

选择排序

遍历数组,选择出最大(小)的数据,将这个最大(小)的数据放在整组数据的最右(左)边,循环整个数组,当循环结束时,得到的数组就是有序的

假设数组最左边的数据i是最小的,把这个数据定义为min

  • 遍历整个数组,当遇到小于min的数据时,把j的位置赋给min所在的位置,并跳出当前循环
  • 交换mini位置的值
  • 再次遍历数组,从i + 1开始

下图是第一次循环的具体过程,剩余的循环类似:
在这里插入图片描述

选择排序优化

遍历数组,同时选择出最大和最小的数据,将最大的数据放在整组数据的最右边,最小的数据放在整组数据的最左边,循环整个数组,当循环结束时,得到的数组就是有序的,同时选择之后,效率明显有所提升

定义数组的最左端为left,最右端为right,初始时将minmax设置为最左端的值,在这个范围内对数组进行排序:

  • 从数组第二项开始循环,找到最大值赋给max,找到最小值赋给min
  • 把最左端的值与min位置的值进行交换,最右端的值与max位置的值进行交换
  • left++,right--,将数组变小
  • 循环上述过程

注:每层内循环中,找到的最值都是当前数组中的最值,完成交换后的值的位置就是最终的位置

在这里插入图片描述
在这里插入图片描述
2、堆排序

交换排序

1、冒泡排序
重复地遍历要排序的序列,依次比较两个相邻的元素,按照想要的顺序(如从大到小、首字母从A到Z)进行交换,当这组序列中不在含有元素,表示排序完成。

基本思路:

  • 从头开始遍历数组,当a[j]>a[j+1]时,交换这两个数,并循环执行,此时最后的元素就是这组序列中最大的那个,它的位置不会再发生改变了;
  • 重复上述步骤

优化一:
假设我们现在排序{1, 2, 3, 4, 5, 6, 7, 8, 10, 9}这组数据,按照上面的排序方式,第一趟排序后将10和9交换已经有序,接下来的8趟排序就是多余的,什么也没做。所以我们可以在交换的地方加一个标记flag,如果那一趟排序没有交换元素,说明这组数据已经有序,不用再继续下去,可提高一定的效率。

优化二:
优化一仅仅适用于连续有序而整体无序的数据(例如:1, 2,3 ,4 ,7,6,5),但是对于前面大部分是无序而后边小半部分有序的数据(例如:1,2,5,7,4,3,6,8,9,10), 它的排序效率也不是很可观,对于这种类型数据,可以再次进行优化。
在循环的过程中可以记下最后一次交换的位置,后边没有交换,必然是有序的,然后下一次排序截止最后一次交换的位置即可,减少了排序的数据,也会提高效率。
在这里插入图片描述

2、快速排序

归并排序

它是建立在归并操作上的一种采用分治法的排序算法,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

简单来说,就是把要排序的无序序列从中间一分为二,分割后的序列再次进行分割,循环分割直至序列中只有一个元素,此时序列中唯一元素是有序的;然后按照分割的顺序反向进行合并,使每个子序列都有序,最终得到的序列就是有序的。

基本思路:
归并排序实际上是一个先分割再合并的算法,分割采用递归的方法是比较容易得到的,难点在于如何合并,而且要使得合并完的序列有序,私以为这才是归并排序的重点。下面给出了相关图解,并有动图展示。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

动图展示:

在这里插入图片描述
提问:归并排序和快速排序都是采用的“分而治之”的思想,那么两者有何不同呢?
归并排序的“分”是拿到一组序列之后,直接从中间一分为二,再递归分割;
快速排序的“分”是拿到一组序列之后,先选取一个基准值,以基准值与其余元素比较大小,大的放在基准值的右侧,小的放在左侧,如此递归分割。

这就意味着,归并排序每次分割完之后,两边的元素数量是基本一致的(若序列内的元素的数量为奇数,则一边比另一边多一);而快速排序在每次分割完之后,两边的元素数量大部分情况下都是不相等的;所以等量数据时,归并排序的效率更高一筹。

总结上述几种排序的性能及时间、空间复杂度如下表:
排序方法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性
直接插入排序O(n2)O(n2)O(n)O(1)稳定
希尔排序O(nlogn)O(n2)O(n)O(1)不稳定
选择排序O(n2)O(n2)O(n2)O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
冒泡排序O(n2)O(n2)O(n)O(1)稳定
快速排序O(nlogn)O(n2)O(nlogn)O(logn)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值