排序算法的分类:

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

排序算法的稳定性:
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,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
来源:oschina
链接:https://my.oschina.net/u/4419899/blog/4277407