这是我参与18月更文挑战的第21天,活动详情查看:2021最后一次更文挑战
分类 | 最好时间复杂度 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定情况 |
---|---|---|---|---|---|
直接插入排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
希尔排序 | 不稳定 | ||||
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 |
冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(nlog2n) | O(n^2) | O(log2n) | 稳定 |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 |
上面主要对比的是排序算法的算法性能分析对比。
其中关于一个算法是否稳定是如何判断的:
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的(来自百度百科)简单来说:假设两个待排序的元素位置a和b 且a在b的前面 位置上对应的关键字是相等的 在排序后他们的相对位置不变则为稳定的
-
直接插入排序 最好的情况就是直接在其后面插入,最坏的情况就是逆序 每次插入都要循环n遍 (这耶可以看出 待排序列越有序 效率就越高 )
-
选择排序
要选数据再把选好的数据放在后面 所以无论序列是否有序时间复杂度都是n^2
- 希尔排序 (缩小增量排序)
他是不稳定的 因为根据希尔排序的过程我们可以看到 每次他是以一个增量来选择一个分组 在这个分组中进行排序 则相对位置就有可能改变
- 冒泡排序
当数据有序是 其不用进行交换 只需要遍历一遍序列即可,但若数据无序 则需要的时间复杂度就是n^2 因为冒泡排序主要是对小于或则大于的数据才会进行交换 所以是稳定的算法
- 快速排序
他的性能好坏主要是对于取这个基准数据要选的好 所以他最好也要nlog2n
- 堆排序
//建堆
void BuildMaxHeap(ElementType A[], int len) {
for (int i = len / 2; i > 0; i--) {
HeadAdjust(A, i, len);
}
}
//调整为大顶堆
void HeadAdjust(ElementType A[], int k, int len) {
A[0] = A[k];
for (int i = 2 * k; i <= len; i *= 2) {
if (i < len && A[i] < A[i + 1]) {i++;}
if (A[i] <= A[0]) break;
else {
A[k] = A[i];
k=i;
}
}
A[k] = A[0];
}
//堆排序 不断调整位置
void HeapSort(ElementType A[], int len) {
BuildMaxHeap(A, len);
for (int i = len; i > 1; i--){
swap(A[i], A[1]); //交换位置
HeadAdjust(A, 1, i - 1);
}
}
复制代码
从上面的代码进行分析 我们建堆 从最后一个非叶子结点向根结点遍历(倒着录)判断其左右子树是否需要调整 调整完后又向上进行比对 调整直到比对到根结点 以此类推 所以根据这个代码可知其时间复杂度为nlog2n