[通俗易懂的C++基础算法] 冒泡排序

本文专门写给萌新看,大佬别捶我 qwq
转自我自己的Blog 传送门

友情提示:到我的Blog食用效果更佳,不过加载速度可能会比较拉胯 XD

冒泡排序

照理先抄他一段百度百科:

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

基本思想

aaaaaaz! 不愧是度娘,能把这么简单的一个算法写这么长的介绍,下面我简单说一下:
你想想,我们要把一串数字进行排序,是不是可以每相邻两个进行一次比较,如果不符合当前的排序规则,就把这两个数字进行交换,那么不可以继续交换的时候,是不是就排完了?

从此引出:

冒泡排序基本思想:每次比较两个相邻的元素,如果这两个元素的顺序错误就把这两个元素交换

举个栗子

我们现在需要把这一个数列【5 4 3 2 1】变成从小到大的顺序

根据冒泡排序的基本思想,我们从头开始依次比较:([]代表比较,如果不符合 $ 前者<后者 $ (因为要变成从小到大,所以 $ 前者 $ 肯定不会比 $ 后者 $ 大),就把它们交换)

1: [5  4] 3  2  1   比较5与4,因为5<4不正确,所以交换 
2:  4 [5  3] 2  1   比较5与3,因为5<3不正确,所以交换
3:  4  3 [5  2] 1   比较5与2,因为5<2不正确,所以交换
4:  4  3  2 [5  1]  比较5与1,因为5<1不正确,所以交换
    4  3  2  1  5   第一轮的结果

放个图片解释一下:
冒泡排序演示图片(修改自《啊哈!算法》

这样,重复很多次这样的操作,就可以得到像这样的数列:【1 2 3 4 5
如果继续对这个数列进行上面的操作,你会发现不管操作多少次,数列都不会有变动了,这就是所谓的排序完成了

那么这里就有一个值得思考的问题了,我们到底应该执行几次从头到尾的比较?这其实就跟需要排序的数列有关了,如果数列像上面一样(把一个从大到小的数列排序为从小到大的数列),那么就需要 数列中有的数字的个数n - 1(可以手动模拟一次,不难发现上面的栗子需要四轮才可以排序好),其他情况就不大好判断了,所以我们每次交换完,需要判断一下这个数列是不是已经排好序了,不然可能会进行多余的操作。

交换

哦哦哦,忘记说交换了

把两个变量中的数值交换过来,其实也有很多很多种方法,这里就列举几种(其实只需要记住第一种)

中介变量

我们可以用一个中介变量t来存储其中的一个变量a的值,然后把已经把值存到中介变量的变量a赋值为另外一个变量b的值,然后再把另外一个变量赋值为中介变量

代码:

void Swap(int & a,int & b) {
	int t=a;
    a=b;
    b=a;
}

加减

我们可以用加减法的一些性质来做到交换,可能看上去不大好理解,为了方便理解,我们把默认把要交换的值设置为xy(还是不理解可以拿)

下面是两个版本:

void Swap(int & a,int & b) {
	a=a+b; // a=x+y b=y
    b=a-b; // a=x+y b=x+y-y=x
    a=a-b; // a=x+y-x=y b=x;
}
void Swap(int & a,int & b) {
	a=a-b; // a=x-y b=y
    b=a+b; // a=x-y b=(x-y)+y=x
    a=b-a; // a=x-(x-y)=y b=x;
}

模板代码

上代码:

const int maxn=1e5; // 数组大小
int a[maxn]; // 数组a 从下标1 开始存数字

void swap(int & a,int & b) { int t=a;a=b,b=t; }

void BubbleSort(int n) { // 排序 在数组 a 中从 1-n 的数字 
	bool Sorted=false; // 排序完成的标志
	while(!Sorted) {
    	//
		for(int i=2;i<=n;i++) { 
			if(a[i-1]>a[i]) {
				swap(a[i-1],a[i]);
			}
		}
        // 判断是否排序完成
        Sorted=true; // 默认当成排序完成了,如果检查的时候发现没完成再把标志变为未完成
        for(int i=2;i<=n;i++) {
        	if(a[i-1]>a[i]) {
            	Sorted=false;
            }
        }
	}
	return ;
}

题目

Luogu P1116 车厢重组

题目要求我们输出相邻元素 交换(划重点 这是用冒泡排序的原因)的次数,那么就需要对上面的模板进行一定的修改……

代码:

const int maxn=1e4+11; // 防止溢出 习惯性写上比题目范围大一点的数字就行
int a[maxn];

int BubbleSort(int n) // 返回交换的次数
	int count=0; // 计数器,每次交换都加一
	bool Sorted=false;
	while(!Sorted) {
		for(int i=2;i<=n;i++) { 
			if(a[i-1]>a[i]) {
				swap(a[i-1],a[i]);
				count+=1; // 计数
			}
		}
        Sorted=true;
        for(int i=2;i<=n;i++) {
        	if(a[i-1]>a[i]) {
            	Sorted=false;
            }
        }
	}
	return count;
}
  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

CornWorld

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值