IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C语言篇】详解“冒泡排序法”--图示、逐步分析、反思、总结归纳、不断优化 -> 正文阅读

[C++知识库]【C语言篇】详解“冒泡排序法”--图示、逐步分析、反思、总结归纳、不断优化

🌍此篇,我们将从最简单的和最原始的方法,来引入冒泡排序法, 进而通过分析过程、图解、不断优化、反思、总结对其深入理解和掌握。


👀博主是一个努力学C的大一生👩?💻,写文章的初衷也是记录自己学习的所得所获所感,并且希望对大家有所帮助,和大家一起学习进步。可能其中有理解不当或者不准确的、不正确的地方,希望大家多多指出!
🎐最后,希望这篇文章能对大家有所帮助!🌷

🛁冒泡排序

🍭引入

首先在可能对于初学者来说,冒泡排序可能比较陌生。
那么先从一个我们比较熟悉的排序题目入手:输入a、b、c三个数,并且按照从大到小的顺序输出。
对于这个题,只有3个数,所以很容易想到的思路是:先把其中一个和另外两个进行比较,找出最大值,剩下的两个数再相互比较,找出最小值(第二大的值)再依次输出即可。
代码可以如下:

#include<stdio.h>

int main()
{
	int a = 0, b = 0, c = 0;
	int temp = 0;//创建一个“中间变量”来实现交换
	scanf("%d %d %d", &a, &b, &c);

	if (a < b)
	{
		temp = a;
		a = b;
		b = temp;//交换a,b的值,使a中放入的是最大值
	}
	if (a < c)
	{
		temp = a;
		a = b;
		b = temp;//通过两个if语句,两次比较和交换,将a中放入最大值
	}
	if (b < c)
	{
		temp = b;
		b = c;
		c = temp;
	}
	printf("%d %d %d", a, b, c);//a,b,c中存放的依次是从小到大的值
}

3个if 语句,实现了3个数字的从大到小的输出。

那4个数字呢?是不是得比较6次?6个if语句?那5个数字?10个数字?哇,简直不敢想象该怎么怎么通过上面的创建单个变量、if语句实现交换来执行了吧!😥

由此,引入了一种比上述排序法相对简单的一种排序方法–冒泡排序法/气泡排序法(至于为什么要叫这个名字,等你了解了之后就会懂啦哈哈)

?(图解)介绍实现过程:

假设输入10个数字,需要按照从小到大的顺序把它输出。
首先我们确定可以优化的是:
1,10个数字,像3个数那样创建单个变量来储存,那肯定不太现实。我们可以创建1个数组来储存这10个数字。
2,if语句来比较是不是太过于麻烦(得写多少行呀,而且内容都差不多)

其实,由第二点,可以引出冒泡排序法的实现:
图解:
第一趟:
在这里插入图片描述
第二趟:
在这里插入图片描述

最终经过9趟这种操作,我们会发现,这时候,顺序就是有序的了:
在这里插入图片描述

🕵??♀?分析过程:

首先,每一趟,我们通过对数组中元素,按顺序,相邻的元素依次进行比较,比较后的结果是:找到了这些比较数字中,最大的那一个元素,并让它落在了正确的位置(最后一个位置),然后第二趟,因为最大的数字已经排好啦,我们需要根据上面的方法,找出剩下9个数字中的最大值(全部数字中第二大值),放在正确的位置(倒数第二个),随后进行第三趟、第四趟…直至数组中的元素成从小到大的有序排列。

🤸?♂?总结规律:

①、每1趟,确定好1个数字的位置。当有n-1(n为数组总元素个数)数字的位置确定好时(剩下一个元素随着也就确定了),整个数组中的元素即为有序排列。所以:n个数字的排列需要进行n-1趟
②、每一趟,需要进行剩余数字间的依次比较来确定“最大值”(这一趟中的最大值,不是所有数字中的最大值,已经排好的数字不参与比较哦),那么每一趟比较的次数应该是这一趟需要比较数字个数(假设为m)再减1,即m-1
③每一趟需要比较的次数和这趟为第几趟有关。(第一趟:找出10个数字中的最大值,需要比9次;第二趟,找出剩余9个数字中的较大值,需要比8次,第三趟,7次…第9趟:比较1次)。所有,假设有n个数字需要排序,需要走n-1趟,则第x趟需要比较n-x次。

其实是不是理解了冒泡排序法的过程后,更加能理解为什么它叫这个了吧。我的理解是,大泡泡(大的数字)沉下去,小泡泡(小的数)随着冒泡排序法的进行就浮上去了。

👩?💻开写代码(逐步实现):

🧐思路:step1:我们需要一个数组来储存我们的元素,首先创建一个数组,并且向它里面输入数据:

#include<stdio.h>
int main()
{
	int arr[10] = {0};//创建一个整形数组
	int i = 0;
	for (i = 0; i < 10; i++)//for循环输入10个数字
	{
		scanf("%d", &arr[i]);
	}
	return 0;
}

step2: 根据上面对冒泡排序法过程的分析,我们需要两个循环,来实现这个过程,因为这个循环与次数有这密切的关系,所以我们选择用两个for循环。
外层for循环:控制趟数(每一趟,排好这一趟中最大值的位置)。
内侧for循环:控制比较次数和交换次数。
💗这里要注意以下前面总结规律中趟数、比较次数和数字个数的关系哦。

	int i = 0;//循环控制变量i、j
	int j = 0;
	for (i = 0; i < N-1; i++)//外层循环:控制趟数
	{
		for (j = 0; j < N - 1 - i; j++)//这里j的作用有2个,第二个是充当元素下标(所以从0开始的好处)
		{
			if (arr[j] > arr[j + 1])//交换
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}

step3:
进行以上两个循环之后,数组里面元素的排列就是从大到小有序排列了,接下来要做的就很简单,再来个for循环把数组中元素依次输出就OK啦!

for ( i = 0; i < N ; i++)//输出
	{
		printf("%d\n", arr[i]);
	}

代码:

#include<stdio.h>
#define N 10
int main()
{
	int arr[N] = {0};//创建一个整形数组
	int temp = 0;//创建一个变量,作用是在交换元素的过程中起到“空瓶”作用
	int i = 0;
	for (i = 0; i < N; i++)//for循环输入10个数字
	{
		scanf("%d", &arr[i]);
	}

	//循环控制变量i、j
	int j = 0;
	for (i = 0; i < N-1; i++)//外层循环:控制趟数
	{
		for (j = 0; j < N - 1 - i; j++)//这里j的作用有2个,第二个是充当元素下标(所以从0开始的好处)
		{
			if (arr[j] > arr[j + 1])//交换
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
	
	for ( i = 0; i < N ; i++)//输出
	{
		printf("%d\n", arr[i]);
	}


	return 0;

}

运行结果:
在这里插入图片描述

🚀代码优化:

1,在完成全部趟数之前,数字已经是有序

假如说我们输入为:1,2,3,4,5,6,7,8,10,9.
这个数组其实已经比较有序了,如果我们用冒泡排序法来进行,它其实第一趟就可以把完成数列的有序化,但是按照这个程序,它不会因为这个时候已经有序了,编译器就不执行后面的趟数了,编译器依旧会傻乎乎的把后面八次原封不动的执行完。这无疑是时间和空间的浪费。那么我们应该如何优化一下,使数字已经排列有序时不再执行后面的操作呢?
我们可以这样想:
如果这一趟进行时,如果数组已经是有序的:交换一次都不发生
如果数组没有达到有序(哪怕像上面只要两个元素交换一下就行):一定会发生交换
利用这一点,我们可以定义一个标记变量:

在这里插入图片描述

#include<stdio.h>
#define N 10
int main()
{
	int arr[N] = {0};//创建一个整形数组
	int temp = 0;//创建一个变量,作用是在交换元素的过程中起到“空瓶”作用
	int i = 0;
	for (i = 0; i < N; i++)//for循环输入10个数字
	{
		scanf("%d", &arr[i]);
	}

	//循环控制变量i、j
	int j = 0;
	for (i = 0; i < N-1; i++)//外层循环:控制趟数
	{
		int flag = 0;//每一趟 中设计一个标记变量
		for (j = 0; j < N - 1 - i; j++)//这里j的作用有2个,第二个是充当元素下标(所以从0开始的好处)
		{
			if (arr[j] > arr[j + 1])//交换
			{
				flag = 1;//如果有元素发生了交换,标记为1

				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
		if (flag == 0)//flag==0说明一次交换都没有发生
		{
			break;
		}

	}
	
	for ( i = 0; i < N ; i++)//输出
	{
		printf("%d\n", arr[i]);
	}


	return 0;

}

2,大多数已经有序

比如1,2,3,6,5,4,7,8,9,10
其实如果按照冒泡排序,前四次都是无用功对吧,因为这个数列的后四项已经是有序啦。那有没有办法省去这个无用功呢?
我们要想,冒泡排序法,它是每一趟,排好一个数,编译器自己是不能直接知道,除了它排好的这些数,前面的是不是有序的,尽管我们能一眼看出来。那站在编译器的角度,虽然它不知道那些没有开始排的数字是不是有序的,但是它可以知道,最后一次交换的元素是第几个,而知道了这个,其实就可以知道从哪里开始是有序的了。
比如上面那个数组:
在这里插入图片描述
于是可以再次优化:
创建一个变量,来记录此趟比较中,最后交换位置的地方,下次循环根据这个来确定比较次数。
在这里插入图片描述

#include<stdio.h>
#define N 10
int main()
{
	int arr[N] = {0};//创建一个整形数组
	int temp = 0;//创建一个变量,作用是在交换元素的过程中起到“空瓶”作用
	int i = 0;
	for (i = 0; i < N; i++)//for循环输入10个数字
	{
		scanf("%d", &arr[i]);
	}

	//循环控制变量i、j
	int j = 0;
	int the_last = N-1;

	for (i = 0; i < N-1; i++)//外层循环:控制趟数
	{
		int flag = 0;//每一趟 中设计一个标记变量
		for (j = 0; j <the_last ; j++)//这里j的作用有2个,第二个是充当元素下标(所以从0开始的好处)
		{
			if (arr[j] > arr[j + 1])//交换
			{
				flag = 1;//如果有元素发生了交换,标记为1

				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
		the_last = j;//注意哦,要写在第二层循环的外头,因为要等一趟比完了,才能确定下一趟的j<the_last

		if (flag == 0)//flag==0说明一次交换都没有发生,直接跳出外层循环
		{
			break;
		}

	}
	
	for ( i = 0; i < N ; i++)//输出
	{
		printf("%d\n", arr[i]);
	}


	return 0;

}

🐬以上就是我关于冒泡排序法的讲解了。如果有说法不准确、错误的地方,希望大家能多多指出,也希望各位能给出你们的想法和建议,我会虚心接受的。希望这篇文章能够帮助到大家,让我们一起进步!🐳

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 11:35:34  更:2022-10-31 11:38:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 5:11:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码