常见排序算法(待补充)

▼魔方 西西 提交于 2020-07-27 20:53:25

排序算法的分类:

常用排序的时间及空间复杂度:

排序算法的稳定性:

     假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

--------------------------------------------------------------------------------------------------

交换排序:

① 冒泡排序

排序原理:

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码实现:

时间复杂度及稳定性:

时间复杂度: O(n2)    【最好、最坏、平均情况都是】

稳定性:稳定的

 

优缺点:

  • 优点:比较简单,空间复杂度较低,是稳定的;
  • 缺点:时间复杂度太高,效率慢;

 

② 快速排序(分治法)

排序原理:双指针法

  • 先从数列中取出一个数作为基准数(比如第一个位置上的数)。
  • 设置左右两个指针i,j,两个指针分别向从左右向对面移动。当左边的指针位置上的数比基准值大,右边指针位置上的数比基准值小,各自停下;
  • 如果i < j时,交换两个指针位置上的数;
  • 当i=j时,两个指针相遇,此时交换基准值与i所在位置的数。这样第一趟的整个流程就结束了。
    • 可以总结每一趟的大致过程是:1 指针就位,交换i,j上的数,指针就位,交换........(i < j)    ----->  2 指针相遇(i = j) ----->3  交换基准值与指针i最后所在位置的数
  • 再对左右区间重复第二步,直到各区间只有一个数。

代码实现:

参考链接:https://blog.csdn.net/fsdgfsf/article/details/103049527

参考链接:https://www.cnblogs.com/captainad/p/10999697.html

时间复杂度及稳定性:

  • 最优解( 快速排序最优的情况就是每一次取到的元素都刚好平分整个数组 ): O( nlogn )
  • 最差解(  最差的情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序) ): O( n^2 )
  • 平均情况: O(nlogn)
  • 快速排序不稳定

 

优缺点:

  • 优点:极快,数据移动少;
  • 缺点:不稳定。

 

归并排序

归并排序(分治策略:递归+合并)

排序原理:

参考链接:https://blog.csdn.net/k_koris/article/details/80508543

视频:https://www.bilibili.com/video/BV114411J7QQ?from=search&seid=9616786909625686379

代码实现:

参考链接:https://www.cnblogs.com/chengxiao/p/6194356.html

时间复杂度及稳定性:

  • 归并排序的最好,最坏,平均时间复杂度均为O(nlogn)
  • 归并排序是稳定排序

优缺点:

优点:

  • 归并排序的效率达到了巅峰:时间复杂度为O(nlogn),这是基于比较的排序算法所能达到的最高境界
  • 归并排序是一种稳定的算法(即在排序过程中大小相同的元素能够保持排序前的顺序,3212升序排序结果是1223,排序前后两个2的顺序不变),这一点在某些场景下至关重要
  • 归并排序是最常用的外部排序方法(当待排序的记录放在外存上,内存装不下全部数据时,归并排序仍然适用,当然归并排序同样适用于内部排序...)

缺点:

  • 归并排序需要O(n)的辅助空间,而与之效率相同的快排和堆排分别需要O(logn)和O(1)的辅助空间,在同类算法中归并排序的空间复杂度略高

 

选择排序

① 堆排序

堆排序是利用这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。

1 准备知识:堆

堆是具有以下性质的完全二叉树

  • 每个结点的值都大于或等于其左右孩子结点的值,称为大顶(根)堆
  • 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶(根)堆

 

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子 :

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]  

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

 

关于索引的一些关系:

查找数组中某个数的父结点和左右孩子结点,比如已知索引为i的数,那么 :

  • 父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)
  • 左孩子索引:2*i+1
  • 右孩子索引:2*i+2

第一个非叶子结点索引: arr.length/2-1;

 

2 堆排序的思想

  • 首先将数组构造成一个大顶堆,取堆顶数字(也就是数组的最大值);
  • 再将剩下的数字构建成一个大顶堆,然后取剩余数字中的堆顶数字(剩余数中的最大值);
  • 重复上述两步骤,知道取完堆中的数字,最后得到一个从小到大的有序数组;

说明:

  • 若想得到从小到大的有序数字,可以在第2步中,先将堆顶数字与末尾的数字交换,然后将前面的剩余数字构建成大顶堆,再取堆顶值;
  • 如果不考虑第2步的交换过程,要得到升序数组采用小顶堆,降序数组采用大顶堆;
  • 如何将数组构建成大顶堆?
    • 从第一个非叶子结点开始,从下至上从右至左逐层扫描,保证根节点要大于它的左右子节点
    • 如果根节点和子节点发生了互换,也不要忘了交换过后,换到子节点上的根节点与原先子节点的左右子节点是否构成大顶堆;

参考链接:https://www.cnblogs.com/liuqiyun/p/9415003.html

参考链接:https://blog.csdn.net/u010452388/article/details/81283998

视频链接:https://haokan.baidu.com/v?vid=6413078055604587741&pd=bjh&fr=bjhauthor&type=video

代码链接:https://www.cnblogs.com/liuqiyun/p/9415003.html

 

 

 

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!