总结
不能用链表实现的排序算法:折半,希尔 ,快速排序
快速排序、堆排序、希尔排序、直接选择排序不是稳定的排序算法
归并排序,快速排序,堆排序,希尔排序 O(nlogn)
归并排序,快速排序,堆排序(一般地)用递归实现
归并:稳定,O(nlogn),递归实现
大类 | 排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 实现方法 | 备注 |
---|---|---|---|---|---|---|
交换法 | 冒泡法 | 最差、平均都是O(n^2),最好是O(n) | 1 | 稳定 | √ | n较小时较好 |
交换法 | 鸡尾酒冒泡法 | 最差、平均都是O(n^2),最好是O(n) | 1 | 稳定 | √ | n较小时较好 |
交换法 | 快速排序 | 平均O(nlogn),最坏是O(n^2) | O(logn) | 不稳定 | √ | n大时较好 |
插入法 | 直接插入法 | 最差、平均都是O(n^2),最好是O(n) | 1 | 稳定 | √ | 大部分已排序时较好 |
插入法 | 折半插入法 | 最差、平均都是O(n^2) | 1 | 稳定 | cuo | 大部分已排序时较好 |
插入法 | 希尔排序(分组的插入法) | 平均是O(nlogn) | 1 | 不稳定 | cuo | |
选择法 | 普通选择 | 最差、平均都是O(n^2) | 1 | 不稳定 | √ | n较小时较好 |
选择法 | 堆排序 | 最差、平均、最好都是O(nlogn) | 1 | 不稳定 | √ | n大时较好 |
归并排序 | 归并排序 | 最差、平均、最好都是O(nlogn) | O(n) | 稳定 | √ | n大时较好 |
基数排序 | 基数排序 | O(n)(d是常数) | O(n) | 稳定 | √ |
不能用链表实现的排序算法:折半,希尔和快速排序
折半插入,希尔排序插入:链表不支持随机访问元素,指针需要长距离移动,每次都要逐个遍历效率实在很慢
快速排序:指针不需要长距离移动,但需要前后向中间移动,可使用双向链表实现,
typedef struct a {int m_iData; struct message *prev, *next }Node, *pNode;
稳定性分析
稳定:相同关键字在排序后相对位置不变
快速排序、希尔排序、堆排序、直接选择排序不是稳定的排序算法,而基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。
冒泡排序:if(arr[j-1]>arr[j]) 交换;
简单选择排序:
基于关键字交换的简单选择排序:if(arr[k]>arr[j]) k=j;寻找最小值,与第一个交换(两个相同值之间没有比较)–不稳定
举个例子,序列3 8 3 2 9, 我们知道第一遍选择第1个元素3会和2交换,那么原序列中2个3的相对前后顺序就被破坏了
基于关键字插入的简单选择排序:链式:if(p->data > q->data) p=q;/p指向最小的关键字/然后插到无序序列的前边,如果不判断是否有序,直接插入一样不稳定
快速排序
快速排序的一次划分的过程是(在高低指针不相遇的条件下)的左右交换
分手时不知你的去处,也没有说我和你何时再相会(一般的,一次划分一定会划分到同一边,但是相对位置是不确定的)
肯定是不稳定的
希尔排序
本来应该相遇的两个数,因为间隔的划分进入了不同的世界,是不稳定的
归并排序-稳定
while(i<length1 && j< length2)
{
if(A1[i]<=A2[j]) arr[k]=A1[i++];/*if的判断条件可保证稳定*/
else
arr[k]=A2[j++];
}