【数据结构与算法——C语言版】5. 排序算法(2)——冒泡排序

news2024/12/26 22:59:54

前言

上篇文章【数据结构与算法——C语言版】4. 排序算法(1)——选择排序我们介绍了排序算法中的选择排序,其时间复杂度是O(n2),本篇文章我们将介绍另一种同样时间复杂度是O(n2)的排序算法——冒牌排序,这两种算法思路不同,但都是两层循环,实用性不高,但有必要通过讲解来掌握不同的算法思路。

冒泡排序核心思想

选择排序的核心思想是每次找到最小值并与第i个元素交换,找n次。
而冒泡排序的核心思想是每次遍历整个数组,比较相邻的两个元素arr[i]和arr[j],将较大者放在arr[j]的位置,然后继续比较arr[j]和arr[j+1];将数组遍历n次后(n为数组元素个数),数组升序有序。
该算法能使数组有序的核心原因如下:

从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。
以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。

用一张图片直观的观察一下:
在这里插入图片描述
第一轮遍历中,总是选择最大的那个数并交换至靠右的位置,第一轮比较完成后,数组中最大的元素50就被“冒”到了右边
最后一轮遍历,arr[0]就是最小的元素2,所以最后一轮遍历没有发生交换,即数组已升序有序。

冒泡排序过程细化

我们还是用一个例子,一步步带着大家来理解冒泡排序的过程。

数组 arr[5] = {5,1,4,2,8},如果采用冒泡排序对其进行升序(由小到大)排序,则整个排序过程如下所示:

  1. 第一次遍历数组arr,两两比较arr[i]和arr[i+1],并将较大者交换到arr[i+1]。第一次遍历前,数组 arr[5] = {5,1,4,2,8};遍历后,数组arr[5] = {1,4,2,5,8};此时arr[4]已经是最大值8,所以下次遍历我们只需要遍历arr[0 ~ 3]
    在这里插入图片描述

  2. 第二次遍历数组arr,两两比较arr[i]和arr[i+1],并将较大者交换到arr[i+1]。第一次遍历前,数组 arr[5] = {1,4,2,5,8};遍历后,数组arr[5] = {1,2,4,5,8};此时arr[3]已经是次大值5,且arr[3~4]保持升序有序;所以下次遍历我们只需要遍历arr[0 ~ 2];
    在这里插入图片描述

  3. 第三次遍历数组arr,两两比较arr[i]和arr[i+1],并将较大者交换到arr[i+1]。第一次遍历前,数组 arr[5] = {1,2,4,5,8};遍历后,数组arr[5] = {1,2,4,5,8}

在这里插入图片描述
4. 第四次遍历数组arr,两两比较arr[i]和arr[i+1],并将较大者交换到arr[i+1]。第一次遍历前,数组 arr[5] = {1,2,4,5,8};遍历后,数组arr[5] = {1,2,4,5,8}
在这里插入图片描述
5. 第五次遍历数组arr,这次我们只需要遍历 arr[0~0];也就是只剩下一个元素arr[0];所以无需比较,产生的数组已经升序有序

在这里插入图片描述

代码描述

void bubbleSort(int arr[], int size)
{
	for (int i = 0; i < size; i++) // 可优化点1
	{
		int count = 0;
		for (int j = 0; j < size - i; j++)	// 每次遍历都会产生一个较大值放到后面,所以第i遍历就只需要比较size - i个元素
		{
			if (arr[j] > arr[j+1])//这是升序排法,前一个数和后一个数比较,如果前数大则与后一个数换位置
			{
				int tem = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tem;
				count = 1;
			}
		}
		if (count == 0) { // 优化点2:如果某一趟没有交换位置,则说明已经排好序,直接退出循环
			break;
		}
	}
}

注释的位置指出了两个优化点
第一个优化点,我们可以修改为 for (int i = 0; i < size - 1; i++)通过上面的图描述,也可以看出实际上n个元素的数组,我们只需要遍历n-1次,第n次遍历时数组只剩下第一个元素“需要”比较,只有一个元素所以可省去多出来的一次循环
第二个优化点,其实已经写出来了,每次遍历比较前,用count记录交换的次数,如果某趟没有发生交换,说明此时数组已经有序,可以直接退出循环
其中,第一个优化点不建议,因为优化跟没优化是一样的,写上size - 1反倒会造成一些误导(因为数组遍历一般都是[0~size))
第二个优化点可以加上,如果待排序数组是 {1,2,3,5,4},这样我们只需要执行一次遍历,节省了很多时间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/146902.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT背后的开源AI框架Ray,现在值10亿美元

Ray 被 OpenAI、亚马逊等科技公司用来开发大模型&#xff0c;是最近异军突起的框架。 最近一段时间&#xff0c;文本生成的人工智能在互联网上掀起了一阵风暴&#xff1a;ChatGPT 因为可以对人们能想到的几乎任何问题提供非常详细、近乎逼真的回答而受到追捧。大模型应用的出现…

Mapper代理开发案例及MyBatis核心

本片文章需要参考我的前一篇文章&#xff1a;MyBatis入门案例引入总结&#xff0c;使用mapper代理开发的好处就是可以解决开发中硬编码的问题和简化后期的SQL执行。使用这种方式可以不用写接口的实现类&#xff0c;免除了复杂的方法&#xff0c;使得代码更加清晰易懂按照以前的…

vue的过渡动画(有vue的动画库和ui库的介绍)

一、概念 Vue 在插入、更新或者移除 DOM 时&#xff0c;提供多种不同方式的应用过渡效果。 二、默认过渡 <template><div><button click"isShow!isShow">显示/隐藏</button><transition appear><h1 v-show"isShow" cl…

过滤器和拦截器的使用及管理

参考&#xff1a;(70条消息) Spring过滤器和拦截器的区别_yjc0403的博客-CSDN博客https://www.cnblogs.com/colin220/p/9606412.htm概述过滤器&#xff1a;是在javaweb中&#xff0c;你传入的request、response提前过滤掉一些信息&#xff0c;或者提前设置一些参数&#xff0c;…

Anaconda安装之后Spyder打不开解决办法--目前有用 jupyter notebook 无法正常运行2023.1.7

纯纯小白&#xff0c;探索一天&#xff0c;终于成功&#xff0c;需要我的经历没有白费&#xff0c;让大家少走弯路。 问题描述 从官网下载Anaconda之后&#xff0c;安装&#xff0c;一切正常。打开Anaconda navigator在弹出窗口选择了更新&#xff08;我怀疑这就根源&#xf…

Js逆向教程24-作用域和自执行函数

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; Js逆向教程24-作用域和自执行函数 一、变量作用域 1.1局部变量 function jb() {var a"我是局部变量"return a; }1.2全局变…

【Java寒假打卡】Java基础-异常

【Java寒假打卡】Java基础-异常异常概述throws声明异常throw抛出异常try-catch 抛出异常throwable的成员方法异常概述 Exception:称之为异常类&#xff0c;他表示程序本身可以处理的问题 RuntimeException及其子类&#xff1a;运行时异常。&#xff08;空指针异常&#xff0c;…

JUC总结系列篇 (二) : 对线程的理解和使用总结

文章内容&#xff1a; 一.为什么需要多线程 二.线程的创建 三.线程的方法sleep(),run(),wait(),yeid(),join(),interrupt()等方法归纳总结 四.线程的状态及其转换 五.线程的交替执行案例 六.多个线程依次执行案例 七.多线程并发带来的线程安全问题 一.为什么需要多线程&#x…

Linux项目自动化构建工具-make/Makefile

一、前言 会不会写makefile&#xff0c;从一个侧面说明了一个人是否具备完成大型工程的能力。一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先编译&#xff0c;哪些文件…

前端入门笔记 04 —— Web(html CSS)布局

响应式布局 屏幕尺寸变化&#xff0c;需要响应式网页设计RWD web页面适应不同屏幕宽度因素 液态站点&#xff0c;拉伸充满浏览器窗口 小屏幕挤成一团&#xff0c;大屏幕空白间隙过大固定宽度 像素为单位固定尺寸 小屏幕滚动&#xff0c;大屏幕空白 实现 设置meta标签媒体查…

数据结构入门5-1(数和二叉树)

目录 注 树和二叉树的定义 树的定义 树的基本术语 二叉树的定义 树和二叉树的抽象数据类型定义 二叉树的性质和存储结构 二叉树的性质 二叉树的存储结构 1. 顺序存储结构 2. 链式存储结构 遍历二叉树和线索二叉树 遍历二叉树&#xff08;traversing binary tree&a…

加密与安全

目录 一、编码算法 1.1、ASCII 1.1.1、ASCII简介 1.1.2、ASCII产生原因 1.1.3、表达方式 1.1.4、标准表 1.1.5、大小规则 1.2、Unicode 1.2.1简介 1.2.2编码和实现 1.3、汉字编码 1.3.1、GB2312-80 标准 1.3.2、GBK 编码标准 1.3.3、GB18030编码标准 1.4、URL编…

【Node】中Express框架连接Mysql实现用户注册接口

Node.js中Express框架连接Mysql实现用户注册接口 处理用户注册接口简单分为三步&#xff1a; 1、注册校验 2、完善逻辑 3、拆分模块 拆分模块能够使部分功能能够复用&#xff0c;封装好各个模块使得模块间只能通过有限的接口互相访问&#xff0c;从而降低耦合&#xff0c;拆分模…

LeetCode[1046]最后一块石头的重量

难度&#xff1a;简单 题目&#xff1a; 有一堆石头&#xff0c;每块石头的重量都是正整数。每一回合&#xff0c;从中选出两块最重的 石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么粉碎的可能结果如下&#xff1a;如果 x …

『年度总结』时光如梭 | 再见 2022 | 你好 2023

⭐创作时间2022年12月31日⭐ ✨结果一直到现在才发&#xff0c;说真的写年度总结还是第一次写比较不熟练&#xff0c;去年有这个活动也有佬叫我参加&#xff0c;不过没参加。今年想着有时间来写下的&#xff0c;结果写到现在才发&#xff0c;这东西说真的挺难写的&#…

机器视觉(九):图像配准

目录&#xff1a; 机器视觉&#xff08;一&#xff09;&#xff1a;概述 机器视觉&#xff08;二&#xff09;&#xff1a;机器视觉硬件技术 机器视觉&#xff08;三&#xff09;&#xff1a;摄像机标定技术 机器视觉&#xff08;四&#xff09;&#xff1a;空域图像增强 …

python简单爬虫

爬虫真是一件有意思的事儿啊&#xff0c;之前写过爬虫&#xff0c;用的是urllib2、BeautifulSoup实现简单爬虫&#xff0c;scrapy也有实现过。最近想更好的学习爬虫&#xff0c;那么就尽可能的做记录吧。这篇博客就我今天的一个学习过程写写吧。 一 正则表达式 正则表达式是一…

格式化电脑重装系统怎么操作

​电脑一但中毒的电脑必须重装系统&#xff0c;而且需要格式化后重装系统&#xff0c;才能将病毒铲除&#xff0c;那么如何将电脑格式化后重装系统呢&#xff1f;能够实现电脑格式化重装系统的方法是U盘重装和光盘重装&#xff0c;由于部分电脑没有光驱&#xff0c;建议用U盘&a…

Redis常见集群方案

Redis常见集群方案 Redis集群方案目前主流的有三种&#xff0c;分别是Twemproxy、Codis和Redis Cluster。 Redis Cluster Redis Cluster 集群是去中心化通过客户端分片的结构&#xff0c;集群元数据信息分布在每个节点上&#xff0c;主备切换依赖于多个节点协商选主。 Red…

C++11之lambda表达式

文章目录一、引入原因二、lambda 表达式的语法1. lambda 表达式各部分说明2.捕捉列表说明三、lambda 表达式的本质一、引入原因 如果待排序元素为自定义类型&#xff0c;需要用户定义排序时的比较规则。 比如&#xff1a; struct Goods {string _name; // 名字double _pr…