什么是冒泡排序
冒泡排序就像他的名字一样,像冒泡一样完成排序。举个栗子,现在有一个数组a如下:
a | Value |
---|---|
a[0] | 2 |
a[1] | 3 |
a[2] | 1 |
我们需要进行两轮冒泡,第一轮先比较a[0]和a[1]谁大谁就在右边(根据具体需求),然后比较a[1]和a[2]。第一轮结束,现在确保了a[2]是所有数组元素中最大的。
a | Value |
---|---|
a[0] | 2 |
a[1] | 1 |
a[2] | 3 |
接着第二轮我们确保倒数第二个元素为最大即可。
a | Value |
---|---|
a[0] | 1 |
a[1] | 2 |
a[2] | 3 |
这个简单的数组就完成了排序。
这就是冒泡排序。如果数组元素为n个,我们就需要n-1次冒泡,每次冒泡确保右边的元素为最大即可。
下面就是最普通的冒泡排序
#include <iostream>
using namespace std;
void swap(int &a , int &b);
int main(){
int a[5] = {2,1,3,5,5};
int length = sizeof(a)/sizeof(a[0]);
for(int i=0;i<length-1;i++){ //0,1,2,3四次冒泡
for(int j=0;j<length-i-1;j++){//第一轮0与1比较,1和2比较 ,2和3比较,3和4比较
if(a[j] > a[j+1]){ //第一轮结束后确定第a[4]一定是最大的
swap(a[j],a[j+1]);
}
}
}
for(int i=0;i<length;i++)
cout<<a[i]<<" ";
return 0;
}
void swap(int &a,int &b){
int temp = a;
a = b;
b = temp;
}
第一次优化
如果我们的数组是这样的话
a | Value |
---|---|
a[0] | 4 |
a[1] | 1 |
a[2] | 2 |
a[3] | 3 |
我们完成了第一次排序后的结果
a | Value |
---|---|
a[0] | 1 |
a[1] | 2 |
a[2] | 3 |
a[3] | 4 |
这个时候数组已经是有序数组了,可以程序没有结束,仍然要继续第二次冒泡,这显然不太好。我们可以用一个变量来表示它第n轮冒泡是否进行了交换。如果没有交换,就证明已经有序。
在这里插入代码片#include <iostream>
using namespace std;
void swap(int &a , int &b);
int main(){
int a[5] = {5,1,2,3,4};
int length = sizeof(a)/sizeof(a[0]);
int flag = 0;
for(int i=0;i<length-1;i++){
flag = 0; //每一轮初始化它为0
for(int j=0;j<length-i-1;j++){
if(a[j] > a[j+1]){
swap(a[j],a[j+1]);
flag = 1;
}
}
if(flag == 0) break; //如果此轮没有交换则有序跳出即可
}
for(int i=0;i<length;i++)
cout<<a[i]<<" ";
return 0;
}
void swap(int &a,int &b){
int temp = a;
a = b;
b = temp;
}
大家可以尝试一下如果注释掉判断时候有序的语句后,程序需要进行4次冒泡,如果有的话程序到第二次冒泡的时候就跳出了。
第二次优化
如果我的数组是这样的话
a | Value |
---|---|
a[0] | 3 |
a[1] | 6 |
a[2] | 2 |
a[3] | 7 |
a[4] | 8 |
我们第一轮冒泡后得到
a | Value |
---|---|
a[0] | 3 |
a[1] | 2 |
a[2] | 6 |
a[3] | 7 |
a[4] | 8 |
此时我们已经知道6,7,8是有序的但是第二轮冒泡仍然在比较6,7这显然是多余的。我么可以记录最后一次交换时的位置(这里是1)。那么a[j+1]即(a[2]) 到a[length-1]即(a[4])一定是有序的。(因为a[2]必然是前3个元素中最大的,a[3]>=a[2],a[4]>=a[3])。我们只需要每次记录最后交换的位置即可。
我们算法书上一般都是给出这种。
#include <iostream>
using namespace std;
void swap(int &a , int &b);
int main(){
int a[5] = {3,2,6,7,8};
int length = sizeof(a)/sizeof(a[0]);
int flag = 0;int temp = length-1;
for(int i=0;i<length-1;i++){
flag = 0; //每一轮初始化它为0
for(int j=0;j<temp;j++){
if(a[j] > a[j+1]){
swap(a[j],a[j+1]);
flag = j; //记录每一次的j值
}
}
temp = flag;
if(flag == 0) break; //如果此轮没有交换则有序跳出即可
}
for(int i=0;i<length;i++)
cout<<a[i]<<" ";
return 0;
}
void swap(int &a,int &b){
int temp = a;
a = b;
b = temp;
}
时间复杂度就是1 + 2 + … + n-1 = 1/2*(n-1)(1+n-1) = 1/2*(n2-n) 就是O(n2)。
它是一种稳定的排序方法(也就是它在排序的时候不会打乱已有的顺序,我的理解)
谢谢大家看完,到此我就说完我所知道的了。