1.直接插入排序
流程:
初始将首个数字当成一个有序数组,然后将第二个数字与第一个数字比对后插入相应的位置并形成新的数组…迭代此过程直到所有数字都插入了新的数组。
时间复杂度:
O(n²)
空间复杂度:
属于就地排序,空间复杂度为O(1)。
稳定性:
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
可视化流程:
2. 希尔排序
流程:
① 先取一个正整数d1(d1 < n)作为第一个增量,将全部n个记录分成d1组,把所有相隔d1的记录放在一组中,即对于每个k(k=1, 2, … d1),R[k], R[d1+k], R[2d1+k] , …分在同一组中,在各组内进行直接插入排序。这样一次分组和排序过程称为一趟希尔排序;
② 取新的增量d2 < d1,重复①的分组和排序操作;直至所取的增量di=1为止,即所有记录放进一个组中排序为止。
时间复杂度:
对希尔排序的复杂度的分析很困难,在特定情况下可以准确地估算关键字的比较和对象移动次数,但是考虑到与增量之间的依赖关系,并要给出完整的数学分析,目前还做不到。
Knuth的统计结论是,平均比较次数和对象平均移动次数在n1.25 与1.6n1.25之间
空间复杂度:
属于就地排序,空间复杂度为O(1)。
稳定性:
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
可视化流程:![这里写图片描述](https://img-blog.csdn.net/20161002100757003)
3.直接选择排序
流程:
从待排序的数据元素集合中选取最小的数据元素并将它与原始数据元素集合中的第一个数据元素交换位置;然后从不包括第一个位置上数据元素的集合中选取最小的数据元素并将它与原始数据元素集合中的第二个数据元素交换位置;如此重复,直到数据元素集合中只剩一个数据元素为止。
时间复杂度:
选择排序的交换操作介于 0 和 (n - 1) 次之间。选择排序的比较操作为 n (n - 1) / 2 次之间。选择排序的赋值操作介于 0 和 3 (n - 1) 次之间。
比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+…+1=n*(n-1)/2。交换次数O(n),最好情况是,已经有序,交换0次;最坏情况交换n-1次,逆序交换n/2次。交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快
空间复杂度:
属于就地排序,空间复杂度为O(1)。
稳定性:
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
可视化流程:
4.堆排序
流程
① 对一组待排序的记录,按堆的定义建立堆;
② 将堆顶记录和最后一个记录交换位置,则前n-1个记录是无序的,而最后一个记录是有序的;
③ 堆顶记录被交换后,前n-1个记录不再是堆,需将前n-1个待排序记录重新组织成为一个堆,然后将堆顶记录和倒数第二个记录交换位置,即将整个序列中次小关键字值的记录调整(排除)出无序区;
④ 重复上述步骤,直到全部记录排好序为止。
时间复杂度:
O(nlogn)
空间复杂度:
只需多出一个堆的空间,空间复杂度为O(1)。
稳定性:
它是不稳定的排序方法。(排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前 和排序后他们的相对位置不发生变化)
可视化流程
5. 冒泡排序
流程:
①比较相邻的元素。如果第一个比第二个大,就交换他们两个。
②对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
③针对所有的元素重复以上的步骤,除了最后一个。
④持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
时间复杂度:
第一遍扫描(N-1)次,第二遍扫描(N-2)次……扫描1次,扫描0次。扫描次数为等差数列。
空间复杂度:
属于就地排序,空间复杂度为O(1)。
稳定性:
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
可视化流程:
改良的冒泡排序—-鸡尾酒排序
6. 快速排序
流程:
①设置两个变量i、j,排序开始的时候:i=0,j=N-1;
②以第一个数组元素作为关键数据,赋值给key,即key=A[0];
③从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;
④从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
⑤重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
时间复杂度:
快速排序的记录移动次数不会大于比较次数,所以,快速排序的最坏时间复杂度为O(n*n);最好时间复杂度为O(nlog2n)。
可以证明,快速排序的平均时间复杂度也是O(nlog2n)。
空间复杂度:
快速排序需要一个栈空间来实现递归。栈的最大深度为 log2 n」 +1,所需栈空间为O(log2 n)。最坏情况下,递归深度为n,所需栈空间为O(n)。
稳定性:
快速排序是不稳定的排序方法。
可视化流程:
7.归并排序
流程:
① 初始时,将每个记录看成一个单独的有序序列,则n个待排序记录就是n个长度为1的有序子序列;
② 对所有有序子序列进行两两归并,得到n/2个长度为2或1的有序子序列——一趟归并;
③ 重复② ,直到得到长度为n的有序序列为止。
时间复杂度:
具有n个待排序记录的归并次数是㏒2n,而一趟归并的时间复杂度为O(n),则整个归并排序的时间复杂度无论是最好还是最坏情况均为O(n㏒2n)。
空间复杂度:
在排序过程中,使用了辅助向量DR,大小与待排序记录空间相同,则空间复杂度为O(n)。
稳定性:
归并排序是稳定的。
可视化流程:
8.基数排序
流程:
基数排序算法的基本思想是:设待排序的数据元素是m位d进制整数(不足m位的在高位补0),设置d个桶,令其编号分别为0,1,2,…,d-1。首先按最低位(即个位)的数值依次把各数据元素放到相应的桶中,然后按照桶号从小到大和进入桶中数据元素的先后次序收集分配在各桶中的数据元素,这样就形成了数据元素集合的一个新的排列,我们称这样的一次排序过程为一次基数排序;再对一次基数排序得到的数据元素序列按次低位(即十位)的数值依次把各数据元素放到相应的桶中,然后按照桶号从小到大和进入桶中数据元素的先后次序收集分配在各桶中的数据元素;这样的过程重复进行,当完成了第m次基数排序后,就得到了排好序的数据元素序列。
时间复杂度:
设有n个待排序记录,关键字位数为d,每位有r种取值。则排序的趟数是d;在每一趟中:
① 链表初始化的时间复杂度:O(r) ;
②分配的时间复杂度:O(n) ;
③分配后收集的时间复杂度:O(r) ;
则链式基数排序的时间复杂度为: O(d(n+r))
空间复杂度:
在排序过程中使用的辅助空间是:2r个链表指针, n个指针域空间,则空间复杂度为:O(n+r)
稳定性:
基数排序是稳定的。
可视化流程:
9.各种排序间的比较
1)从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
2)从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于希尔排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
3)从稳定性看:直接插入排序、冒泡排序和归并排序是稳定的;而希尔排序、直接选择排序、快速排序和堆排序是不稳定排序。
4)从待排序的记录数n的大小看,n较小时,宜采用简单排序;而n较大时宜采用改进排序。
9.如何选择排序方法
1)当待排序记录数n 较大时,若要求排序稳定,则采用归并排序。
2)当待排序记录数n 较大,关键字分布随机,而且不要求稳定时,可采用快速排序;
3)当待排序记录数n 较大,关键字会出现正、逆序情形,可采用堆排序(或归并排序)。
4)当待排序记录数n 较小,记录已接近有序或随机分布时,又要求排序稳定,可采用直接插入排序。
5)当待排序记录数n 较小,且对稳定性不作要求时,可采用直接选择排序。