1. 回顾
之前学习过的排序算法有:归并排序、堆排序、快速排序、快速选择排序、基数排序、桶排序、计数排序、希尔排序、插入排序。其中不稳定的排序算法为堆、快、希、直接选择(区分快速选择),其他都是稳定排序。现在补充两个基础排序算法:冒泡和直接选择排序。
2. 冒泡排序
比较简单,可以直接看代码:
for(int i=0;i<nums.size();++i)
//每次当前最大的数都会被交换到末尾
for(int j=0;j+1<nums.size();++j)
if(nums[j]>nums[j+1])
swap(nums[j],num[j+1]);
如果做一些for
的优化为:
//总共只需要n-1次
for(int i=nums.size();i>1;--i)
//j无需到末尾
for(int j=0;j+1<i;++j)
if(nums[j]>nums[j+1])
swap(nums[j],nums[j+1]);
时间复杂度
根据for
的优化版本来看,
T
(
n
)
=
O
(
n
−
1
+
n
−
2
+
n
−
3
+
.
.
.
.
.
+
1
)
=
O
(
n
2
)
T(n)=O(n-1+n-2+n-3+.....+1)=O(n^2)
T(n)=O(n−1+n−2+n−3+.....+1)=O(n2),最好情况的时间复杂度同样也是
O
(
n
2
)
O(n^2)
O(n2),比起最坏情况时间复杂度会有常数项的提升。
3. 直接选择排序
直接选择排序是对冒泡排序的优化,观察上面的代码也知道没必要每次都swap
,可以将swap
次数减少到最坏n-1
次。只需要每次有一个变量记录最大值的位置,代码如下:
//总共只需要n-1次
for(int i=nums.size();i>1;--i){
int flag=0;
for(int j=1;j<i;++j)
if(nums[j]>nums[flag])
flag=j;
if(flag != i-1)
swap(nums[flag],nums[i-1]);
}
时间复杂度
因为直接选择排序是冒泡排序的优化,这个优化是常数项优化。所以其最好和最坏时间复杂度依然为 O ( n 2 ) O(n^2) O(n2)。
4. 总结
冒泡和直接选择的实现方式有多种,上面是笔者写的一种实现。无论怎么样实现和优化,总体上都是 O ( n 2 ) O(n^2) O(n2)的最坏时间复杂度。