冒泡排序(Bubble Sort),是一种简单的交换排序算法。
原理:
- 相邻元素比较后,小的浮起来,大的沉下去。
- 每次外循环都至少有一个元素完成排序。
- 持续重复比较,未排序元素越来越少,直到没有元素需要比较。
举例:
输入:nums = {2, 4, 7, 3, 1}
循环次数/下标 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
0 | 2 | 4 | 7 | 3 | 1 |
1 | 2 | 4 | 3 | 1 | 7 |
2 | 2 | 3 | 1 | 4 | 7 |
3 | 2 | 1 | 3 | 4 | 7 |
4 | 1 | 2 | 3 | 4 | 7 |
- 冒泡第一版:
void bubbleSort(vector<int>& nums){
for(int i = 0; i < nums.size() - 1; ++i){
for(int j = 0 ; j < nums.size() - 1 - i; ++j){// 每次外循环至少有一个元素完成排序
if(nums[j] > nums[j + 1])
swap(nums[j], nums[j + 1]);
}
}
}
这里我们可以思考一下,这个算法是否可以优化呢?
答案是肯定的,上面的例子可能体现不出来,如果我们的输入数组的数据情况是:nums = {1, 2, 3, 4, 7, 5, 6, 8}
,这里其实只要外循环一次就能解决问题。如何优化这个冗余重复比较的过程呢?引入一个变量来记录是否发生交换,如果没发生则可以退出循环了。
- 冒泡第二版:
void bubbleSort(vector<int>& nums){
for(int i = 0; i < nums.size() - 1; ++i){
// 记录是否没发生交换
bool flag = true;
for(int j = 0; j < nums.size() - 1 - i; ++j){
if(nums[j] > nums[j + 1]){
flag = false;
swap(nums[j], nums[j + 1]);
}
}
// 如果没发生交换,则退出
if(flag == true)
return;
}
}
在第二版后,我们再来思考一下,是否能继续优化呢?
如果想不出?我们可以举个例子:nums = {2, 1, 4, 3, 5, 6, 7, 8, 9}
,在这个例子中你会发现数组后半部分是有序,所以前面两种算法前5次有冗余比较。
- 冒泡第三版:
void bubbleSort(vector<int>& nums){
// 边界,右边有序
int border = nums.size() - 1;
for(int i = 0; i < nums.size() - 1; ++i){
bool flag = true;
// 记录发生最后一次交换的下标
int last = 0;
for(int j = 0; j < border; ++j){
if(nums[j] > nums[j + 1]){
last = j;
flag = false;
swap(nums[j], nums[j + 1]);
}
}
border = last;
if(flag == true)
return;
}
}
最后
思考在两次优化后,冒泡算法是否还能优化呢?