冒泡排序思路详解
基本思路:每次遍历数组的时候,比较相邻的两个数的大小,如果左数大于右数则进行交换(这里我们从小到大进行排序,如果时是从大到小的排序则是左数小于右数的时候进行交换)。总共的遍历次数是n-1次。
如图:
- 第一轮遍历如下:
2. 第二轮遍历如下:(粉色竖线即指其后续元素有序)
3. 其实此时我们的数组已经有序,但是机器不知道哇,它还需要遍历两次,将会结束整个排序过程。所以我们冒泡的优化也是根据这个进行改进的,如果在某一轮遍历的过程中我们没有交换操作,就意味着我们的数组已经达到了有序的状态。
冒泡排序代码
在这一部分我将会给出三个版本的代码,一种是为了便于理解的将冒泡分成了两个函数来完成,一种是直接使用一个函数来完成,最后一种则是对冒泡排序进行了改进。
为了便于理解我们首先将冒泡排序分为两个函数来完成,其中一个是子函数用于完成一次冒泡的过程,具体如下:
void bubble(int* a, int n) {
for(int i=0; i<n-1; ++i){
if(a[i] > a[i+1]){
SWAP(a[i], a[i+1]); // 交换
}
}
}
冒泡排序过程如下:
void bubble_sort(int* a, int n) {
for(int i=n; i>0; i++){
bubble(a, i);
}
}
我们也可以使用一个函数来完成冒泡排序如下:
void bubble_sort(int* a, int n) {
for(int i=n; i>0; i++){
for(int j=0; j<i-1; ++j){
if(a[j] > a[j+1]){
SWAP(a[i], a[j+1]);// 交换
}
}
}
}
改进代码如下:增加一个布尔量用于标志某一轮是是否进行了交换操作,根据之前的分析我们知道若一次冒泡的遍历过程中没有仅进行交换操作则是排序完成。
void bubble_sort(int* a, int n) {
bool is_swap = false;
for(int i=n; i>0; i++){
for(int j=0; j<i-1; ++j){
if(a[j] > a[j+1]){
SWAP(a[i], a[j+1]); // 交换
is_swap = true;
}
}
if(is_swap == 0){
break;
}
}
}
SWAP是设置的交换的宏定义,如下:
#define SWAP(a,b) { int t = a ; a = b ; b = t; }
冒泡性能分析
时间复杂度 | O(N^2) |
---|---|
空间复杂度 | O(1) |
稳定性 | 稳定 |
注意:
- 当数组原本就有序,使用优化的代码时间复杂度为O(N)。
- 稳定性即指,当数组中相同值的元素在排序算法结束之后他们的前后顺序不发生改变。冒泡排序可以有稳定性,前提是我们设置的交换操作的条件不包括相等的情况(也就是我们使得相邻的两个数在相等时不进行交换即可)。