vlambda博客
学习文章列表

经典排序算法之冒泡排序(Bubble Sort)

冒泡排序 ( Bubble Sort )

冒泡排序,正如它的名字一样,未排序数组中的最大(小)值会依次往上浮。冒泡排序主要有两个基本步骤:相邻元素之间的比较 和 交换位置。

步骤分析:

令待排序序列为 data,规模为 n ,按照升序进行排序,则冒泡排序的步骤可以总结为:

  1. 从第一个元素开始,在两相邻元素之间进行比较,如果前一个元素 大于 后一个元素,则交换位置,否则 没有操作。

  2. 然后比较第二个元素 和 第三个元素。如果第二个元素 大于 第三个元素,则交换位置,否则 没有操作。

  3. 一直比较到第 n-1 和第 n 个元素( n为待找出最大数字的序列的规模 ),找出这 data[0] 到 data[n-1] 这 n 个数据中最大的数字。此时,最大的数字会被放在 data[n-1] 的位置,即最后面。

  4. 重复步骤 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)。冒泡排序算法为就地排序。

稳定性

当两相邻元素大小相等时,不会触发交换操作,他们的相对位置也不会发生变化。因此,冒泡排序算法是稳定的。