手撕排序算法3:优化版冒泡排序和快速排序的三种方法(包括三数取中,小区间优化,递归版本)(上)

简介: 手撕排序算法3:优化版冒泡排序和快速排序的三种方法(包括三数取中,小区间优化,递归版本)(上)

一.冒泡排序

1.算法思想

冒泡排序,顾名思义,就是在每一趟中将最大的数沉到水底,也就是将最大的数移动到末尾位置,一共进行n-1次

冒泡排序的整体思想是:

1.左右两两比较,大的向后移动,小的向前移动

2.每一趟都会使当前所比较过的元素中最大的那个移动到最后位置

3.一共n-1趟即可,因为对于一个数组来说,如果已经确定好了n-1个数字,又因为一个数组只有n个数字,所以剩下的那一个数字的位置也就唯一确定了

2.代码实现

void BubbleSort(int* a, int n)
{
  int i = 0;
  for (i = 0; i < n - 1; i++)//一共冒泡n-1趟(i控制趟数)
  {
    int flag = 1;//假设有序
    int j = 0;
    for (j = 0; j < n - 1 - i; j++)//(j控制每一趟比较的次数)
      //第一趟比较n-1次,第二趟比较n-2次(因为第二趟就不需要比较最后一个数字了,因为最后一个数字已经是最大的了)....,归纳为n-1-i次
    {
      if (a[j] > a[j + 1])
      {
        Swap(&a[j], &a[j + 1]);
        flag = 0;//发生交换,改为无序
      }
    }
    if (flag == 1)//有序,所以无需再进行排序,直接break
    {
      break;
    }
  }
}

这是冒泡排序的一种优化版本,使用flag标志数组是否已经有序,如果有序,则跳出循环,排序成功.

3.冒泡排序的时间复杂度与稳定性

冒泡排序的时间复杂度是O(N^2),具有稳定性

至于为什么冒泡排序具有稳定性呢?

是因为冒泡排序在每一趟的比较过程中只有当左边元素大于右边元素时才会发生交换,而当左边元素等于右边元素时并不会发生交换,所以冒泡排序具有稳定性

4.冒泡排序,插入排序,选择排序的优劣介绍

插入排序比冒泡排序好,冒泡排序比选择排序好

前面提到过,当数组是有序或者部分有序时,插入排序有奇效(时间复杂度能达到O(N)!!!)

可是我们刚才进行的冒泡排序的优化也可以减少一些不必要的比较啊,那么它们两个到底谁更好呢?

下面给大家举个例子.

总结:优化版本冒泡排序

时间复杂度:O(N^2)

最好排序:O(N)

最差:O(N^2)

1.跟直接插入排序相比来说,直接插入更好

因为:

插入排序的任意性更强,对有序,接近有序,局部有序的适用性更强,所以说直接插入排序是在O(N^2)中的排序算法中非常好的一个算法了

2.很直接选择排序相比来说,冒泡排序更好,因为直接选择排序无论数组是否有序,都进行N^2次,而冒泡排序针对有序或部分有序有一些优化,避免了一些没有任何必要的比较

3.但是数组无序的情况下,冒泡排序还是效率比较差的

二.快速排序

1.算法思想

快速排序是一个非常强大的排序算法,能够很快地解决大多数排序问题,但是要理解起来不是很容易,我们先来看一下快排的单步思想

那么我们该如何实现让6的左边都比6小,6的右边都比6大呢?

下面我们介绍一下"挖坑"法,pivot:英文单词"坑"

我们来看这几张图片

这就是单趟快排的示意图.

2.单趟快排的代码实现

接下来,我们先写一下单趟快排的代码

void QuickSort(int* a, int n)
{
  int begin = 0;
  int end = n - 1;
  int pivot = begin;
  int key = a[begin];
  while (begin < end)
  {
    //左边有坑,右边找小,放到左边
    while (a[end] >= key && begin < end)
    {
      end--;
    }
    if (begin < end)
    {
      //小的放到左边的坑里,自己形成了新的坑位
      a[pivot] = a[end];
      pivot = end;
    }
    //右边有坑,左边找小,放到右边
    while (a[begin] <= key && begin < end)
    {
      begin++;
    }
    if (begin < end)
    {
      //大的放到右边的坑里,自己形成了新的坑位
      a[pivot] = a[begin];
      pivot = begin;
    }
  }
  pivot = begin;
  a[pivot] = key;
}

可见,单趟排序的时间复杂度是O(N),因为begin和end要相遇,且每轮循环只能有一个"指针"在变动,这里所说的"指针"不是C语言所说的指针,而是一种标记而已

3.快排整体思想和代码实现

这时,我们成功让6的左边都小于6,6的右边都大于6,

此时我们想:

如果能让6的左边变为有序,右边也变为有序,那么不就整体有序了吗?

所以在这里我们呢考虑使用分治的思想,也就是递归的方法,也就是缩短区间(大事化小,将一个大问题拆解为若干个子问题,然后逐个击破)

因为当区间缩小到只剩一个值的时候,它一定有序

下面我们来看一张图片

我们发现,只需要对第一次分割出来的左区间和右区间分别进行多次挖坑法,就可以实现整体有序,

其实我们发现,这个快排的递归思想就像是二叉树的深度优先遍历.

下面我们用代码实现一下,如果感觉理解不了下面代码中的这种递归的方式,请仔细看一下上面这张图片,上面把递归调用的整个过程划分的很详细

void QuickSort(int* a, int left,int right)//这里为了进行函数递归,把形参改为左右"指针",方便进行递归
{
  if (left >= right)//当区间长度小于等于1时,无需进行排序了,如果不加这一条,函数将进入死递归
  {
    return;
  }
  int begin = left;
  int end = right;
  int pivot = begin;
  int key = a[begin];
  while (begin < end)
  {
    //左边有坑,右边找小,放到左边
    while (a[end] >= key && begin < end)
    {
      end--;
    }
    if (begin < end)
    {
      //小的放到左边的坑里,自己形成了新的坑位
      a[pivot] = a[end];
      pivot = end;
    }
    //右边有坑,左边找小,放到右边
    while (a[begin] <= key && begin < end)
    {
      begin++;
    }
    if (begin < end)
    {
      //大的放到右边的坑里,自己形成了新的坑位
      a[pivot] = a[begin];
      pivot = begin;
    }
  }
  pivot = begin;
  a[pivot] = key;
  //这里我们将[left,right]这个区间分为这么三个部分
  //[left,pivot-1]  pivot [pivot+1,right]
  QuickSort(a, left, pivot - 1);
  QuickSort(a, pivot + 1, right);
  //快排的递归思想就像是二叉树的深度优先遍历.
  //根 左区间 右区间 根 左区间 右区间 根 左区间 右区间 根 左区间 右区间 .........,
  //单个区间就像是叶子节点
}

上面就是快排的基础代码(还未经过优化的)

相关文章
|
14天前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
12天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于生物地理算法的MLP多层感知机优化matlab仿真
本程序基于生物地理算法(BBO)优化MLP多层感知机,通过MATLAB2022A实现随机数据点的趋势预测,并输出优化收敛曲线。BBO模拟物种在地理空间上的迁移、竞争与适应过程,以优化MLP的权重和偏置参数,提升预测性能。完整程序无水印,适用于机器学习和数据预测任务。
|
6天前
|
算法 安全 数据安全/隐私保护
基于BBO生物地理优化的三维路径规划算法MATLAB仿真
本程序基于BBO生物地理优化算法,实现三维空间路径规划的MATLAB仿真(测试版本:MATLAB2022A)。通过起点与终点坐标输入,算法可生成避障最优路径,并输出优化收敛曲线。BBO算法将路径视为栖息地,利用迁移和变异操作迭代寻优。适应度函数综合路径长度与障碍物距离,确保路径最短且安全。程序运行结果完整、无水印,适用于科研与教学场景。
|
13天前
|
算法 数据安全/隐私保护
基于二次规划优化的OFDM系统PAPR抑制算法的matlab仿真
本程序基于二次规划优化的OFDM系统PAPR抑制算法,旨在降低OFDM信号的高峰均功率比(PAPR),以减少射频放大器的非线性失真并提高电源效率。通过MATLAB2022A仿真验证,核心算法通过对原始OFDM信号进行预编码,最小化最大瞬时功率,同时约束信号重构误差,确保数据完整性。完整程序运行后无水印,展示优化后的PAPR性能提升效果。
|
4天前
|
算法 数据可视化 调度
基于NSGAII的的柔性作业调度优化算法MATLAB仿真,仿真输出甘特图
本程序基于NSGA-II算法实现柔性作业调度优化,适用于多目标优化场景(如最小化完工时间、延期、机器负载及能耗)。核心代码完成任务分配与甘特图绘制,支持MATLAB 2022A运行。算法通过初始化种群、遗传操作和选择策略迭代优化调度方案,最终输出包含完工时间、延期、机器负载和能耗等关键指标的可视化结果,为制造业生产计划提供科学依据。
|
7天前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
9天前
|
机器学习/深度学习 资源调度 算法
基于入侵野草算法的KNN分类优化matlab仿真
本程序基于入侵野草算法(IWO)优化KNN分类器,通过模拟自然界中野草的扩散与竞争过程,寻找最优特征组合和超参数。核心步骤包括初始化、繁殖、变异和选择,以提升KNN分类效果。程序在MATLAB2022A上运行,展示了优化后的分类性能。该方法适用于高维数据和复杂分类任务,显著提高了分类准确性。
|
2天前
|
算法 数据安全/隐私保护 异构计算
基于LSB最低有效位的音频水印嵌入提取算法FPGA实现,包含testbench和MATLAB对比
本项目展示了一种基于FPGA的音频水印算法,采用LSB(最低有效位)技术实现版权保护与数据追踪功能。使用Vivado2019.2和Matlab2022a开发,完整代码含中文注释及操作视频。算法通过修改音频采样点的最低有效位嵌入水印,人耳难以察觉变化。然而,面对滤波或压缩等攻击时,水印提取可能受影响。该项目运行效果无水印干扰,适合实时应用场景,核心逻辑简单高效,时间复杂度低。
|
2天前
|
算法 数据安全/隐私保护
基于GA遗传算法的拱桥静载试验车辆最优布载matlab仿真
本程序基于遗传算法(GA)实现拱桥静载试验车辆最优布载的MATLAB仿真,旨在自动化确定车辆位置以满足加载效率要求(0.95≤ηq≤1.05),目标是使ηq尽量接近1,同时减少车辆数量和布载耗时。程序在MATLAB 2022A版本下运行,展示了工况1至工况3的测试结果。通过优化模型,综合考虑车辆重量、位置、类型及车道占用等因素,确保桥梁关键部位承受最大荷载,从而有效评估桥梁性能。核心代码实现了迭代优化过程,并输出最优布载方案及相关参数。
|
7天前
|
机器学习/深度学习 存储 算法
基于MobileNet深度学习网络的活体人脸识别检测算法matlab仿真
本内容主要介绍一种基于MobileNet深度学习网络的活体人脸识别检测技术及MQAM调制类型识别方法。完整程序运行效果无水印,需使用Matlab2022a版本。核心代码包含详细中文注释与操作视频。理论概述中提到,传统人脸识别易受非活体攻击影响,而MobileNet通过轻量化的深度可分离卷积结构,在保证准确性的同时提升检测效率。活体人脸与非活体在纹理和光照上存在显著差异,MobileNet可有效提取人脸高级特征,为无线通信领域提供先进的调制类型识别方案。