通俗解释冒泡排序及其两次优化

什么是冒泡排序
  冒泡排序就像他的名字一样,像冒泡一样完成排序。举个栗子,现在有一个数组a如下:

aValue
a[0]2
a[1]3
a[2]1

我们需要进行两轮冒泡,第一轮先比较a[0]和a[1]谁大谁就在右边(根据具体需求),然后比较a[1]和a[2]。第一轮结束,现在确保了a[2]是所有数组元素中最大的。

aValue
a[0]2
a[1]1
a[2]3

接着第二轮我们确保倒数第二个元素为最大即可。

aValue
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;
}

第一次优化

  如果我们的数组是这样的话

aValue
a[0]4
a[1]1
a[2]2
a[3]3

我们完成了第一次排序后的结果

aValue
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次冒泡,如果有的话程序到第二次冒泡的时候就跳出了。

第二次优化

  如果我的数组是这样的话

aValue
a[0]3
a[1]6
a[2]2
a[3]7
a[4]8

我们第一轮冒泡后得到

aValue
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)。
它是一种稳定的排序方法(也就是它在排序的时候不会打乱已有的顺序,我的理解)

谢谢大家看完,到此我就说完我所知道的了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值