排序一
排序一
Q: 为什么插入排序比冒泡排序更受欢迎?
经典的排序算法
排序算法 | 时间复杂度 | 是否基于比较 |
---|---|---|
冒泡、插入、选择 | O(n^2) | Y |
快排、归并 | O(n*logn) | Y |
桶、计数、基数 | O(n) | N |
如何分析一个排序算法?
排序算法的执行效率
- 最好情况、最坏情况、平均情况时间复杂度
- 时间复杂度的系数、常数、低阶
- 比较次数和交换(移动)次数
排序算法的内存消耗
- 空间复杂度
- def "原地排序": 特指空间复杂度为O(1)的排序算法
排序算法的稳定性
- 稳定性的概念是说,如果待排序的序列中存在值相等的元素,经过排序后,相等元素之间原有的先后顺序不变。
- Example: 给订单系统排序,先按下单时间排序然后再按价格排序。
冒泡排序
function bubble(arr){
var len = arr.length;
var flag = false;
for(var i = 0; i<len-1;i++ ){
for(var j = 0; j < len -1 - i; j++){
var tmp = arr[j];
if(arr[j]>arr[j+1]){
arr[j] = arr[j+1];
arr[j+1] = tmp;
flag = true;
}
}
if(!flag) break;
}
return arr;
}
插入排序
function insertSort(arr){
var len = arr.length;
for(var i = 1; i < len;++i){
var value = arr[i];
for(var j = i-1;j>=0;--j){
if(arr[j] > value){
arr[j+1] = arr[j];
}else break;
}
arr[j+1] = value;
}
return arr;
}
选择排序
function seSort(arr){
var len = arr.length;
for(var i = 0; i < len -1; i++){
var min = i;
for(var j = i+1; j<len;j++){
if(arr[j]<arr[min]){
min = j;
}
}
if(min!=i){
var tmp = arr[min];
arr[min] = arr[i];
arr[i] = tmp;
}
}
return arr;
}
三种排序算法的思想及实现
- 推荐一个动画演示的网址:十种排序算法
补充
-
“有序度”: 是指数组中具有有序关系的元素队的个数。有序元素对用数学表示如下:
有序元素对:a[i] <= a[j], 如果 i < j。
-
“满有序度”:
$$
n*(n-1)/2
$$ -
逆序度 = 满有序度 - 有序度,【移动次数等于逆序度】
用有序度分析冒泡排序的平均时间复杂度
- 对于包含 n 个数据的数组进行冒泡排序,平均交换次数是多少呢?最坏情况下,初始状态的有序度是 0,所以要进行 n(n-1)/2 次交换。最好情况下,初始状态的有序度是 n(n-1)/2,就不需要进行交换。我们可以取个中间值 n(n-1)/4,来表示初始有序度既不是很高也不是很低的平均情况。换句话说,平均情况下,需要n(n-1)/4次交换操作,比较操作肯定要比交换操作多,而复杂度的上限是O(n2),所以平均情况下的时间复杂度是O(n2)。
思考
若使用链表这种数据结构,以上三种排序算法相应的复杂度会怎么变化?