排序算法总结一,简单排序算法

有一张盗百度百科的图,百科好像也是盗某个博主的图
盗的图,见谅

我们先比较简单算法,因为简单算法和复杂算法没啥可比较的。

简单的排序算法有:简单选择排序,冒泡排序,直接插入排序,详细的论述及实现请看各自的文章
几种算法的思路都很直接,复杂度都是n^2,我们假设是升序排序来描述。

冒泡排序:

两两比较,将较大值移到后面,这样一趟完成后,最大值会移动到数组末尾。然后重复这个过程,将剩下的元素两两比较,最大值移动到最后。
时间复杂度:n^2
稳定性:只会相邻元素交换,可以实现为稳定算法

直接插入排序:

从第二个数开始,将每个数,插入前面已排好数的合适的位置。通过轮询找到合适的位置,该位置以及之后的数全部往后移动一位,将当前位置的数放到目标位置去,叫做插入排序。
由于前面的数组有序,找到插入合适位置的方法可以通过二分查找法来实现,所以有个二分插入排序的改进版。
时间复杂度:n^2
稳定性:相邻元素交换,稳定算法

选择排序:

轮询整个数组 ,从未排序的数据中找出最小值,放到第一位,将第一位的数交换到后面的空位上(交换)。依次将剩下数组中的最小值找出来,放到剩下元素的第一位,直到找完。
时间复杂度:n^2
稳定性:不相邻元素交换,不稳定算法
反例:假设一个数组为5 2 5 1,第一次会找到最小值1,将5和1交换,1 2 5 5 ,前面的5跑到了第二个5的后面,稳定性已经被打破。

三种O(n^2)算法的比较:

假设数据中有n个长度的数组,其中总体违反次序数m个
效率:选择排序 > 插入排序 > 冒泡排序
已冒泡排序复杂度做1个单位来看
插入排序 = 1 / 3冒泡复杂度
* 选择排序 小于 1 / 3 冒泡复杂度*
冒泡排序每一次都要比较,如果违反顺序需要交换,比较n次,交换m次,交换相当于三次赋值,所以是3m
插入排序,不用二分法的插入排序,因为找到比base大的值,寻找可以提前退出,从概率上讲,提前退出会出现在任意地方,平均起来是n/2次,比较整体会比冒泡排序少一半,如果使用二分,更是只要logn次。
找到base的位置后,后面的数整体要往后移动一次,移动相当于一次赋值,是交换的1/3。
假设一个数在x位置,前面的都比它大,最终x要移动到最前面,也就是某个元素要移动x-1次。对于插入排序,找到base位置后,该位置所有的数都要往后移动一位,该位置和第一个位置交换一次,交换相当于三次赋值,所以总体3+(x - 1),也就是x + 2。对于冒泡排序,是需要一步步的交换来实现的,交换x - 1次,赋值3(x - 1)次,所以交换消耗大约是冒泡的 1 / 3。
这样整体看下来,插入排序的速度大约是冒泡的2~3倍(快2~3倍)。.我对这个结论心存疑惑,决定去验证一把。
冒泡有个优化的过程,记录每次交换顺序,当交换次数为0时,说明已经有序,可以提前退出。但是假设数据已经有序,对于插入排序,后面的逻辑是,也仅仅只是查找位置而已,因为有序,当前位置元素不再需要交换。所以这个优化对于他们之间的速度关系带不来多大影响。

选择排序每次要比较n次,但是一次只需要交换一次,也就是比较和冒泡相同,取决于整体需要交换的次数,也就是取决于数组的有序程度,取极限情况,假设完全倒序,冒泡需要交换n-1,n-2,,,1,也就是 (n-1)*(n-2)/2次,选择需要交换n-1次;完全有序,冒泡需要交换0次,选择也需要交换0次,这个时候完全相同。可以看出选择排序应该绝对优于冒泡排序。

选择排序和插入排序其实并不具有可比性,一个比较次数少,一个交换次数少。如果硬要比,选择排序交换次数会比冒泡排序多,取决于是否使用二分,一次会多n/2或者(n - logn)次。比较次数选择排序一次是一个交换,插入排序是一个交换,m个位移(赋值),一次多m个位移,所以这俩并没有可比性,取决于长度和乱序程度,理论上长度越长乱序程度就会越大,但是乱序的增长会超过线性的增长,所以随机情况下,应该选择排序更快一点。

上面的排序都只能在相邻数之间进行比较,所以时间复杂度公式都是O(n^2),冒泡排序、插入排序由于是相邻的交换,所以能保证稳定性;选择排序进行的是不相邻的交换,所以丢失稳定性

相邻交换有个很大的缺陷,假设5 4 3 2 1,5最终要移动到最后,只能一步步的挪过去。

猜你喜欢

转载自blog.csdn.net/u011531425/article/details/80628951