【C语言】深入理解冒泡排序算法(优化+详解)

简介: 【C语言】深入理解冒泡排序算法(优化+详解)

文章目录

什么叫冒泡排序

冒泡排序是比较基础的排序算法之一,其思想是相邻的元素两两比较,较大的数下沉,较小的数冒起来,这样一趟比较下来,最大(小)值就会排列在一端。

整个过程如同气泡冒起,因此被称作冒泡排序

通俗来说,也就是:

从第一个元素开始比较相邻的两个元素,如果第一个比第一个大或小,就互换它们的位置,这样先比较完一次,然后抛弃最大或最小的继续比较,直到排序完成。

冒泡排序的步骤:

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 每趟从第一对相邻元素开始,对每一对相邻元素作同样的工作,直到最后一对。
  • 针对所有的元素重复以上的步骤,除了已排序过的元素(每趟排序后的最后一个元素),直到没有任何一对数字需要比较。

动画演示:

此处引用网上一张比较经典的gif来展示冒泡排序的整个过程:


image.png

图解冒泡排序

有8个数组组成一个无序数列:5,8,6,3,9,2,1,7,希望从小到大排序。


image.png

按照冒泡排序的思想:把相邻的两个数字两两比较,当一个数字大于右侧相邻的数字时,交换他们的位置,当一个数字和他右侧的数字小于或等于的时候,不交换。

第一轮排序

  1. 首先让5和8进行交换,发现5比8小,因此元素位置不变;
  2. 接下来让8和6比较,发现8比6大,所以要交换8和6的位置;

image.png

  1. 继续让8和3比较,发现8比3要大,所以8和3 交换位置;

image.png

  1. 继续让8和9进行比较,发现8比9小,不用交换;
  2. 9和2进行比较,发现9比2大,进行交换;

image.png

  1. 继续让9和1进行比较,发现9比1大,所以交换9和1的位置;

image.png

  1. 最后,让9和7交换位置;

image.png

这样一来,元素9作为数列的最大元素,就已经排序好了

image.png

第二轮排序

  1. 首先让5和6比较,发现5比6小,位置不变;
  2. 接下来让6和3比较,发现6比3大,交换位置;

image.png

  1. 接下来让6和8比较,6比8小,位置不变;
  2. 8和2比较。8比2大,交换位置;

image.png

  1. 接下来让8和1比较,8比1大,因此交换位置;image.png
  2. 继续让8和7比较,发现8比7大,交换位置;

image.png

这样一来,第二轮排序已经好了

image.png

第三轮排序

按照以上步骤,可得第三轮排序:

image.png

第四轮排序

按照以上步骤,可得第四轮排序:

image.png

第五轮排序

按照以上步骤,可得第五轮排序:

image.png

第六轮排序

按照以上步骤,可得第六轮排序:

image.png

第七轮排序

按照以上步骤,可得第七轮排序,此时已经有序了:

image.png

第八轮排序

此时已经排序完成啦!

image.png

到此为止,所有的数字都是有序的了,冒泡排序是一种稳定排序,由于该排序算法的每一轮都要遍历所有的数字,一共要遍历n-1,所以时间复杂度为O(n^2)

那么我们如何区分排序算法是否稳定呢?

如果我们交换的时候,遇到两个相同的数字;

如果两个相同的数字在排序之后相对位置没有交换,那么就是稳定的排序,反之则是不稳定的排序。

代码实现

代码过程如下:

void bubble_sort(int* arr, int sz)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < sz - 1; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
  }
}
int main()
{
  int arr[10] = { 5, 8, 6, 3, 9, 2, 1, 7 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, sz);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
 }

运行结果:

image.png

这个代码很简单,使用双循环的方式进行排序。

外部的循环控制所有回合,内部循环代表每一轮的冒泡处理,先进行元素比较,再进行元素交换。

代码优化

从上面的例子不难看出,我们可以对原来的冒泡排序进行优化。

我们仍然用上面呢个数列{ 5, 8, 6, 3, 9, 2, 1, 7 }为例子,从上面的图解可以看出在第六、第七、第八轮排序后,整个数列已经是有序的了,但是排序算法还是执行到了第八轮排序。

image.png

优化的思路是:如果能判断出数列已经是有序的了,并且做出标记,那么就不会执行多余的排序。

因此,我们可以进行一个优化,就是设置一个flags;

  • 如果在本轮排序中有元素进行交换,则说明数列无序,如果已经排序了那么设置为0;
  • 如果在本轮排序中,没有元素进行交换,则说明数列有序,那么设置为1。

现在我们来看看优化后的代码:

void bubble_sort(int* arr, int sz)
{
  int i = 0;
  int j = 0;
  int flags = 0;
  for (i = 0; i < sz - 1; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
        flags = 1;//不是有序的,flags设置为1
      }
    }
    if (flags == 0)
      return;
  }
}
int main()
{
  int arr[8] = { 5, 8, 6, 3, 9, 2, 1, 7 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  printf("排序前: ");
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
  bubble_sort(arr, sz);
  printf("排序后: ");
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
 }

运行结果:

image.png

以上就是冒泡排序啦!

如有错误,欢迎指正话😊!

相关文章
|
28天前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
52 4
|
9天前
|
算法
基于大爆炸优化算法的PID控制器参数寻优matlab仿真
本研究基于大爆炸优化算法对PID控制器参数进行寻优,并通过Matlab仿真对比优化前后PID控制效果。使用MATLAB2022a实现核心程序,展示了算法迭代过程及最优PID参数的求解。大爆炸优化算法通过模拟宇宙大爆炸和大收缩过程,在搜索空间中迭代寻找全局最优解,特别适用于PID参数优化,提升控制系统性能。
|
16天前
|
存储 关系型数据库 分布式数据库
PolarDB的PolarStore存储引擎以其高效的索引结构、优化的数据压缩算法、出色的事务处理能力著称
PolarDB的PolarStore存储引擎以其高效的索引结构、优化的数据压缩算法、出色的事务处理能力著称。本文深入解析PolarStore的内部机制及优化策略,包括合理调整索引、优化数据分布、控制事务规模等,旨在最大化其性能优势,提升数据存储与访问效率。
23 5
|
1月前
|
存储 算法 数据管理
C语言算法复杂度
【10月更文挑战第20天】
C语言算法复杂度
|
29天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
78 8
|
1月前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
29天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
76 7
|
1月前
|
人工智能 算法 大数据
Linux内核中的调度算法演变:从O(1)到CFS的优化之旅###
本文深入探讨了Linux操作系统内核中进程调度算法的发展历程,聚焦于O(1)调度器向完全公平调度器(CFS)的转变。不同于传统摘要对研究背景、方法、结果和结论的概述,本文创新性地采用“技术演进时间线”的形式,简明扼要地勾勒出这一转变背后的关键技术里程碑,旨在为读者提供一个清晰的历史脉络,引领其深入了解Linux调度机制的革新之路。 ###
|
2月前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。
|
1月前
|
存储 缓存 算法
优化轮询算法以提高资源分配的效率
【10月更文挑战第13天】通过以上这些优化措施,可以在一定程度上提高轮询算法的资源分配效率,使其更好地适应不同的应用场景和需求。但需要注意的是,优化策略的选择和实施需要根据具体情况进行详细的分析和评估,以确保优化效果的最大化。