一、直接插入排序
待排序数组:A[0..n-1],
排序思路:首先我们认为A[0]是已经排好序的,在排序过程中,依次将A[i](i=1,2,...,n-1)从后往前插入到前面已经
排好序的子数组A[0..i-1]中的适当位置中,待所有的A[i]插入完毕,即排序完毕。
算法如下:
空间上,该算法仅需要常数个辅助单元,空间复杂度为O(1)
时间上,该算法的主程序执行了n-1趟,显然,记录的初始排列对排序过程中记录的比较次数和移动次数都
有影响。
最好的情况下,即初始序列有序,则每次循环只需与前一个记录比较一次,且不需要移动,总的比较次
数为n-1,移动次数为0;
最坏的情况下,即初始序列逆序,则每个记录A[i]都需要与之前的子数组中的所有记录进行比较,总的比较
次数达到最大,总的移动次数也达到了最大。
所以,直接插入排序的时间复杂度为O(n^2),它是一种稳定的排序算法。
二、折半插入排序
折半插入排序的基本原理与直接插入排序相同
不同之处:(1)确定当前记录在前面有序子数组中的位置时,直接插入排序是采用顺序查找法, 而折半插入排
序是采用折半查找法,(2)直接插入排序,边比较边移动元素,而折半插入排序则将比较和移动操作
分离,即先查找出元素的待插入位置,然后再同意地移动带插入位置之后的所有元素。
算法如下:
相对于直接插入排序,折半插入排序算法仅仅是减少了比较元素的次数,它的比较次数与初始序列无关,仅取决
于序列中的元素个数n
时间复杂度为O(n^2),为稳定排序算法。
三、希尔排序
又称为缩小增量排序,
基本思想:先将待排序序列分割成若干个字表,分别进行直接插入排序,待整个表中元素呈基本有序时,再对全
体记录进行一次直接插入排序。
算法如下:
希尔排序只需一个记录的辅助空间,它是一种不稳定的排序算法。
四、冒泡排序
基本思想:假设待排序表长为n,从后向前/从前向后两两比较相邻元素的值,若为逆序,则交换他们,直到序列
比较完成,这称为一趟冒泡,结果将最小的元素交换到待排序列的第一个位置,下一趟排序时,则前面一趟确定的最
小原序不再参与比较,待排序列减少一个元素,每趟冒泡的结果是将序列中的最小元素放到了序列的最终位置
算法如下:
时间复杂度为O(n^2),它仅使用了常数个辅助单元,空间复杂度为O(1),为稳定的排序算法
五、快速排序
快速排序是在冒泡排序的基础上改进而来的,它是基于分治的思想。下面对一个典型子数组A[left...right]排序的
分治过程的三个步骤:
分解:数组A[left...right]被划分为两个子数组A[left...q-1]和A[q+1...right],使得A[left...q-1]中的每个元素都小于等
于A[q],A[q+1...right]中的每个元素都大于等于A[q];
解决:通过递归调用快速排序,对子数组A[left...q-1]和A[q+1...right]排序;
合并:由于两个子数组均是在原地进行排序的,故此时已经得到有序的序列了。
算法如下:
快速排序的运行效率与划分对称有关。
最坏的情况:在两个分区,分别包含n-1个和0个元素,这种最大程度的不对称性若发生在每一层递归上,就得到
时间复杂度为O(n^2);因此快速排序在最坏情况下并不比插入排序号。此外,当输入数组已经是完全排好序时,快速
排序的运行时间也为O(n^2)。同样情况下, 插入排序的运行时间为O(n);
最理想的情况:也就是分区做到最平衡的划分,得到的两个子数组的大小都不可能>n/2.这种情况下,快速排序
的运行速度将大大的提升。时间复杂度O(nlog2n)
由于快速排序是递归的,所以需要一个栈来存放每一层递归调用的必要信息,其最大容量与递归电泳的深度一
致。最好情况下为栈的深度为O(log2n);最坏情况下,需进行n-1次递归调用,栈的深度为O(n);平均情况下,栈深
为O(log2n)。
快速排序是一种不稳定的排序方法。
六、选择排序
排序思想:每一趟(如第i趟)在后面n-i+1个待排序元素中选取关键字最小的元素,最为有序序列的第i个元素,
共需进行n-1趟。
算法如下:
整个排序过程供需选择n-1次,第i趟选择最小元素所比较的次数为n-i次,与初始序列无关,因此,总的比较次数
为n(n-1)/2
若初始序列有序,则整个排序过程中的元素移动次数为0,相反,逆序情况下,则每个元素都需要进行1次交换、
3次移动,元素移动的总次数为3(n-1)
选择排序的时间复杂度为O(n^2),为不稳定排序。