各种排序的稳定性、时间复杂度、空间复杂度的总结

 1.直接插入排序

原理:对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

核心:假设第一个元素排好,之后的元素对排好的部分从后向前比较,并逐一移动。

2.希尔排序

希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分组进行插入排序,随后逐步缩小增量,继续按组进行直接插入排序操作,直至增量为1。希尔排序通过这种策略使得整个数组在初始阶段达到从宏观上看基本有序,小的基本在前,大的基本在后。然后缩小增量,到增量为1时,其实多数情况下只需微调即可,不会涉及过多的数据移动。

3.直接选择排序

它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

4.堆排序

堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次大值。如此反复执行,便能得到一个有序序列了

5.冒泡排序

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

6.快速排序

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

从数列中挑出一个元素,称为 “基准”(pivot);
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

7.归并排序

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略:

  当我们要排序这样一个数组的时候,归并排序法首先将这个数组分成一半。

  然后想办法把左边的数组给排序,右边的数组给排序,之后呢再将它们归并起来。当然了当我们对左边的数组和右边的素组进行排序的时候,再分别将左边的数组和右边的数组分成一半,然后对每一个部分先排序,再归并。

 

 对于上面的每一个部分呢,我们依然是先将他们分半,再归并,

 分到一定细度的时候,每一个部分就只有一个元素了,那么我们此时不用排序,对他们进行一次简单的归并就好了。如图:

 归并到上一个层级之后继续归并,归并到更高的层级,如图

 直至最后归并完成。

  

归并细节:

比如有两个已经排序好的数组,如何将他归并成一个数组?我们可以开辟一个临时数组来辅助我们的归并。

整体来讲我们要使用三个索引来在数组内进行追踪。

 蓝色的箭头表示最终选择的位置,而红色的箭头表示两个数组当前要比较的元素,比如当前是2与1比较,1比2小,所以1放到蓝色的箭头中,蓝色的箭头后移,1的箭头后移。

 然后2与4比较,2比4小那么2到蓝色的箭头中,蓝色箭头后移,2后移,继续比较.......

 归并思路就是这样了,最后唯一需要注意的是那个先比较完的话,那么剩下的直接不需要比较,把后面的直接移上去就可以了,这个需要提前判定一下。

8.计数排序

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。它只能对整数进行排序。

  • 找出待排序的数组中最大和最小的元素;
  • 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

9.适用场景

快排是最好的,其次是归并和希尔,堆排序在数据量很大时效果明显

快排:
一般情况时排序速度最块,但是不稳定,当有序时,反而不好;

归并排序:
稳定,适合大规模的排序,Array.sort()使用的就是归并排序;

堆排序:
适合数据量很大的情况,例如:大数据处理的一个例子:找出一千万个数中最小的前一百个数;
思路:建立一百个节点的大顶堆,首先将前一百个数放入堆中,之后每放入一个数就删除一个堆顶元素,最后剩下的就是最小的一百个数。当然也可以分区处理,感兴趣的小伙伴可以网上搜一下大神们的帖子。

希尔排序:
对增量的标准没有较为满意的答案,增量对性能会有影响;

归并排序:
效率非常不错,在数据规模较大的情况下,比希尔排序和堆排序要好;

 

posted @ 2020-04-20 22:08  藤原拓海7  阅读(878)  评论(0编辑  收藏  举报