经典排序算法之冒泡排序(Bubble Sort)
冒泡排序 ( Bubble Sort )
冒泡排序,正如它的名字一样,未排序数组中的最大(小)值会依次往上浮。冒泡排序主要有两个基本步骤:相邻元素之间的比较 和 交换位置。
步骤分析:
令待排序序列为 data,规模为 n ,按照升序进行排序,则冒泡排序的步骤可以总结为:
从第一个元素开始,在两相邻元素之间进行比较,如果前一个元素 大于 后一个元素,则交换位置,否则 没有操作。
然后比较第二个元素 和 第三个元素。如果第二个元素 大于 第三个元素,则交换位置,否则 没有操作。
一直比较到第 n-1 和第 n 个元素( n为待找出最大数字的序列的规模 ),找出这 data[0] 到 data[n-1] 这 n 个数据中最大的数字。此时,最大的数字会被放在 data[n-1] 的位置,即最后面。
重复步骤 1 到 步骤 3 ,一直比较到待找出最大数字的序列的规模为 1 ,因为只剩一个元素,所以就不用比较了。
如下图,该数据序列 data 一共有5个元素,他们为 [ 5, 3, 4, 1, 2 ] ,下图给出了找出 data 序列中最大数字 5 的冒泡过程。
代码( C++ ):
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int size = nums.size();
if(size<=1)return nums;
// 外层循环可以看做 1. 冒泡排序的趟数(一共比较 size-1 趟) 2. 浮起的第 i 个最大的数字
for(int i=1; i<size; i++){
bool flg = true; // 记录待排序数组是否有序,有序为 true,
// 每次都从第一个元素开始,比较相邻的两个元素,找出未排序数组中的最大值,一直到
for(int j=0; j<size-i; j++){
if(nums[j]>nums[j+1]){ // 触发交换的条件
int tmp = nums[j+1];
nums[j+1] = nums[j];
nums[j] = tmp;
flg = false; // 如果待排序数组发生交换,则说明是无序的
}
}
if(flg) break;
}
return nums;
}
};
本段代码多了一个标志变量 flg,flg 是用来标记剩下的序列中有没有发生交换的,如果没有发生交换,说明剩下的序列是有序的,就不需要再傻傻地都比较一遍了,可以提前结束排序。
分析:
从时间复杂度、空间复杂度、稳定性三个方面对冒泡排序进行分析。
时间复杂度
最好时间复杂度:当待排序列已经是有序的,我们只需要一次冒泡操作就可以退出排序流程,因此最好时间复杂度为 O(n)。
最坏时间复杂度:当待排序列是倒序时,需要进行 n-1 次冒泡排序,因此最坏时间复杂度为 O(n²)。
空间复杂度
冒泡排序只有在交换的时候会申请内存辅助交换操作,所申请的内存空间大小是常量级的,与数据规模 n 无关,因此空间复杂度为 O(1)。冒泡排序算法为就地排序。
稳定性
当两相邻元素大小相等时,不会触发交换操作,他们的相对位置也不会发生变化。因此,冒泡排序算法是稳定的。