当前位置: 首页 > news >正文

【一文了解】八大排序-冒泡排序、选择排序

目录

复杂度和稳定性

1.冒泡排序

1.1.核心逻辑

1.2.适用场景

1.3.复杂度

1.4.稳定性

1.5.举例

1)核心动作拆解

2)实例分析([3,1,4,2]升序为例)

1.6.代码实现

2.选择排序

2.1.核心逻辑

2.2.适用场景

2.3.复杂度

2.4.稳定性

2.5.举例

1)核心动作拆解

2)实例分析([3,1,4,2]升序为例)

2.6.代码实现

3.测试

3.1.完整代码

3.2.测试结果

总结


       本篇文章来分享一下八大排序中的冒泡排序与选择排序。

复杂度和稳定性

       首先来了解一下算法中复杂度和稳定性的概念,以便更好地了解排序,其中复杂度包括时间复杂度和空间复杂度。

1)时间复杂度:基于“操作次数的数学建模”

       时间复杂度描述算法执行时间随数据规模n增长的趋势(取最高阶项,忽略常数和低阶项),推导核心是统计“基本操作”的执行次数(如比较、交换、移动元素)。

2)空间复杂度:额外存储空间的需求

       空间复杂度衡量算法所需的额外存储空间(不包括输入数据)

3)稳定性:相同元素的相对位置是否改变

稳定性由算法的“交换/移动逻辑”决定。相同元素的相对位置不改变是稳定排序,如冒泡排序仅相邻交换,相等不交换,而相同元素的相对位置改变是不稳定排序,如选择排序跨位置交换最值,可能打乱相同元素顺序。

1.冒泡排序

1.1.核心逻辑

       重复遍历数组,相邻元素两两比较,逆序则交换;每轮将"最大/最小"元素"冒泡"到对应位置

1.2.适用场景

       小规模数据(n<1000)、几乎有序的数据(可触发提前退出优化)

1.3.复杂度

1)时间复杂度:O (n²)(最坏/平均),O(n)(最优)

●最坏情况(完全逆序):逆序对数量为n(n-1)/2内层循环每轮n-i-1次比较(共(n-1)+(n-2)+...+1=n(n-1)/2次,最高阶 n²),需 n-1 轮,每轮 n-i-1 次比较,总比较次数 O (n²)。

●最优情况(完全有序):逆序对数量为0,加标志位后仅需1轮n-1次比较,总比较次数O (n)。

●平均情况(随机数据):逆序对数量的平均值约为n(n-1)/4(仍为 n² 阶)。无论数据如何随机,每轮都需要比较“未排序部分的相邻元素”,平均需要n/2轮,每轮平均n/2次比较,总比较次数约为n/2*n/2= n²/4,仍属于O (n²)阶(忽略常数系数)。

2)空间复杂度:O(1)(原地排序)

1.4.稳定性

       稳定,即相同元素不改变相对位置

1.5.举例

1)核心动作拆解

相邻比较:每次只比较数组中相邻的两个元素(如arr[j]和arr[j+1])。

逆序交换:若相邻元素反序(升序时前大后小,降序时前小后大),则交换两者位置。

逐轮冒泡:每完成一轮遍历,当前未排序部分的“最大元素”(升序)或“最小元素”(降序)会像气泡一样“浮”到数组的末尾(已排序部分)。

2)实例分析([3,1,4,2]升序为例)

第1轮:比较(3,1)→交换→[1,3,4,2];比较(3,4)→不换;比较(4,2)→交换→[1,3,2,4]。本轮结束,最大元素4冒泡到末尾。

第2轮:比较(1,3)→不换;比较(3,2)→交换→[1,2,3,4]。本轮结束,次大元素3冒泡到倒数第2位。

第3轮:无交换(数组已序),提前退出。

1.6.代码实现

/// <summary>
/// 冒泡排序
/// </summary>
/// <param name="arr">待排序数组(会直接修改原数组)</param>
/// <param name="isAscending">排序方向:true=升序(从小到大),false=降序(从大到小)</param>
public static void BubbleSort<T>(T[] arr, bool isAscending = true) where T : IComparable<T>
{//校验输入:空数组或长度为1,无需排序if (arr == null || arr.Length <= 1) return;int n = arr.Length;//外层循环:控制排序轮次(最多n-1轮,因每轮确定1个元素位置)for (int i = 0; i < n - 1; i++){bool hasSwapped = false;//标记本轮是否发生交换(优化:无交换则数组已序,提前退出)//内层循环:遍历未排序部分,相邻元素比较交换//每轮后,末尾i个元素已有序,无需再遍历for (int j = 0; j < n - i - 1; j++){//比较相邻元素:根据排序方向判断是否逆序int compareResult = arr[j].CompareTo(arr[j + 1]);bool needSwap = isAscending ? (compareResult > 0) : (compareResult < 0);if (needSwap){//交换元素(C# 7.0+ 解构赋值语法,简洁高效)(arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);hasSwapped = true;}}//本轮无交换,说明数组已完全有序,直接退出循环(关键优化)if (!hasSwapped) break;}
}

2.选择排序

2.1.核心逻辑

       每次从"未排序部分"找到"最小/最大"元素,放到"已序部分"的"末尾",逐步扩大有序范围。

2.2.适用场景

       小规模数据、对交换次数敏感的场景(如硬件存储介质读写成本高时)

2.3.复杂度

1)时间复杂度:O (n²)(最坏/平均/最优)

●最坏情况下(逆序):每个元素需移动i次(i从1到n-1),总移动次数1+2+...+(n-1)=n(n-1)/2,时间复杂度O(n²)。

●平均情况(随机数据):时间复杂度O(n²)

●最优情况(完全有序):比较次数仍为n(n-1)/2,仅移动次数为0(无需交换),时间复杂度O(n²)。

2)空间复杂度:O(1)(原地排序)

2.4.稳定性

       不稳定(如[2,2,1],第一个2会与1交换,破坏相同元素相对位置)

2.5.举例

1)核心动作拆解

:每轮只找一次最值(内层循环仅比较,不交换)。

:每轮只交换一次(最值与未排序部分的第一个元素)。

:已排序部分从左到右逐步扩大,最终覆盖整个数组。

2)实例分析([3,1,4,2]升序为例)

初始:未排序[3,1,4,2],已排序[]。

第1轮:找到最小值1,与未排序第一个元素3交换→数组变为[1,3,4,2]。已排序[1],未排序[3,4,2]。

第2轮:从[3,4,2]找最小值2,与未排序第一个元素3交换→数组变为[1,2,4,3]。已排序[1,2],未排序[4,3]。

第3轮:从[4,3]找最小值3,与未排序第一个元素4交换→数组变为[1,2,3,4]。已排序[1,2,3],未排序[4](自然有序)。

2.6.代码实现

/// <summary>
/// 选择排序
/// </summary>
/// <param name="arr">待排序数组(会直接修改原数组)</param>
/// <param name="isAscending">排序方向:true=升序,false=降序</param>
public static void SelectionSort<T>(T[] arr, bool isAscending = true) where T : IComparable<T>
{if (arr == null || arr.Length <= 1) return;int n = arr.Length;//外层循环:控制有序部分范围(i为未排序部分的起始索引)//有序部分最开始为空for (int i = 0; i < n - 1; i++){//步骤1:找到未排序部分的" 目标元素(最值) "索引(升序找最小,降序找最大)int targetIndex = i;for (int j = i + 1; j < n; j++){int compareResult = arr[j].CompareTo(arr[targetIndex]);bool needSwap = isAscending ? (compareResult < 0) : (compareResult > 0);if (needSwap){targetIndex = j;//更新 目标元素(最值) 索引}}//步骤2:将 目标元素(最值) 与未排序部分第一个元素交换(若 目标元素(最值) 就是第一个,无需交换)if (targetIndex != i){(arr[i], arr[targetIndex]) = (arr[targetIndex], arr[i]);}}
}

3.测试

3.1.完整代码

using System;
using System.Collections.Generic;
using UnityEngine;public class SortTest : MonoBehaviour
{private void Start(){int[] arr1 = GenerateArray(10);PrintArray(arr1);BubbleSort(arr1);PrintArray(arr1, "冒泡排序后,数组内容");int[] arr2 = GenerateArray(10);PrintArray(arr2);SelectionSort(arr2);PrintArray(arr2, "选择排序后,数组内容:");}private int[] GenerateArray(int count, int minValue = 0, int maxValue = 100){List<int> arr = new List<int>();for (int i = 0; i < count; i++){int value = UnityEngine.Random.Range(minValue, maxValue);arr.Add(value);}return arr.ToArray();}/// <summary>/// 冒泡排序/// </summary>/// <param name="arr">待排序数组(会直接修改原数组)</param>/// <param name="isAscending">排序方向:true=升序(从小到大),false=降序(从大到小)</param>public static void BubbleSort<T>(T[] arr, bool isAscending = true) where T : IComparable<T>{//校验输入:空数组或长度为1,无需排序if (arr == null || arr.Length <= 1) return;int n = arr.Length;//外层循环:控制排序轮次(最多n-1轮,因每轮确定1个元素位置)for (int i = 0; i < n - 1; i++){bool hasSwapped = false;//标记本轮是否发生交换(优化:无交换则数组已序,提前退出)//内层循环:遍历未排序部分,相邻元素比较交换//每轮后,末尾i个元素已有序,无需再遍历for (int j = 0; j < n - i - 1; j++){//比较相邻元素:根据排序方向判断是否逆序int compareResult = arr[j].CompareTo(arr[j + 1]);bool needSwap = isAscending ? (compareResult > 0) : (compareResult < 0);if (needSwap){//交换元素(C# 7.0+ 解构赋值语法,简洁高效)(arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);hasSwapped = true;}}//本轮无交换,说明数组已完全有序,直接退出循环(关键优化)if (!hasSwapped) break;}}/// <summary>/// 选择排序/// </summary>/// <param name="arr">待排序数组(会直接修改原数组)</param>/// <param name="isAscending">排序方向:true=升序,false=降序</param>public static void SelectionSort<T>(T[] arr, bool isAscending = true) where T : IComparable<T>{if (arr == null || arr.Length <= 1) return;int n = arr.Length;//外层循环:控制有序部分范围(i为未排序部分的起始索引)//有序部分最开始为空for (int i = 0; i < n - 1; i++){//步骤1:找到未排序部分的" 目标元素(最值) "索引(升序找最小,降序找最大)int targetIndex = i;for (int j = i + 1; j < n; j++){int compareResult = arr[j].CompareTo(arr[targetIndex]);bool needSwap = isAscending ? (compareResult < 0) : (compareResult > 0);if (needSwap){targetIndex = j;//更新 目标元素(最值) 索引}}//步骤2:将 目标元素(最值) 与未排序部分第一个元素交换(若 目标元素(最值) 就是第一个,无需交换)if (targetIndex != i){(arr[i], arr[targetIndex]) = (arr[targetIndex], arr[i]);}}}/// <summary>/// 打印数组内容/// </summary>/// <param name="arr"></param>public static void PrintArray<T>(T[] arr, string prefix = "数组内容:") where T : IComparable<T>{if (arr == null){Debug.Log($"{prefix} null");return;}Debug.Log($"{prefix} [{string.Join(", ", arr)}]");}
}

3.2.测试结果

总结

       冒泡排序是 “多交换、少比较(最优情况)、稳定”,选择排序是 “少交换、多比较(固定)、不稳定”。两者均为基础的原地比较类排序算法,核心逻辑简单但时间复杂度较高(平均/最坏均为O (n²)),适合小规模数据排序。

对比维度

冒泡排序(BubbleSort)

选择排序(SelectionSort)

核心逻辑

重复遍历数组,相邻元素两两比较,逆序则交换;每轮将"最大/最小"元素"冒泡"到对应位置;可加“无交换标志”优化。

 每次从"未排序部分"找到"最小/最大"元素,放到"已序部分"的"末尾",逐步扩大有序范围。

时间复杂度

最坏/平均:O(n²)(需完整比较+交换);最优:O(n)(完全有序,加标志位后1轮比较无交换)。

最坏/平均/最优:O(n²),因为找最值必须遍历完未排序部分,比较次数固定为n(n-1)/2。

空间复杂度

O(1)(原地排序,仅需临时变量存储交换元素)

O(1)(原地排序,仅需临时变量存储最值索引和交换元素)

稳定性

稳定(相邻元素交换时,相同值不交换,保留原相对顺序)

不稳定(最值与首位元素交换时,可能打乱相同值的相对顺序

适用场景

小规模数据(n<1000)、几乎有序的数据(可触发提前退出优化)

小规模数据、对交换次数敏感的场景

       好了,本次的分享到这里就结束啦,希望对你有所帮助~

http://www.dtcms.com/a/525890.html

相关文章:

  • 【电脑软件】视频画质视频修复工具v3.0(支持GPU加速)
  • 违法网站怎么做安全网站建设方案报价表
  • 网站建设logo显示怎么设置网站是做响应式还是自适应的好
  • 网站建设中静态页面模板购物类型网站建设
  • h5可以来做网站吗寓意好的商贸公司名字
  • 软文网站发布平台申请微信支付公司网站
  • 怎么向google提交网站重庆玖玺国际做网站
  • Linux 环境下实现简单的标准TFTP服务器
  • const和explicit关键字
  • 建设植绒衣架网站wordpress discuz论坛模板
  • MapAnything: 通用前馈式度量3D重建
  • (springboot+vue前后端分离部署)阿里云windows服务器部署
  • 优质聊城做网站费用杭州 app开发公司
  • springboot——@Scheduled为什么顺序执行
  • 做一个网站需要多少人域名查询网中国万网
  • 【Java面向对象编程(OOP)的三大基本特性】
  • 潍坊网站商品网站怎么做的
  • 响应式网站页面设计福彩网站开发
  • 专做婚纱店设计网站网站设计软件开发
  • 上海网站建设口碑最好的公司低成本门户网站开发
  • Watch and Learn: Semi-Supervised Learning of Object Detectors from Videos
  • 北京网站开发报价到那个网站做翻译接单
  • 云蛇吞路懂车赛-游戏程序系统方案
  • 自己做网站不想买空间 自己电脑可以做服务器吗?yu网站建设
  • 网站建设费能入长期待摊吗网站建设及网页设计教案
  • h5网站欣赏wordpress搜索调用
  • DepthAI V3.1.0 正式版发布!
  • 网络课程网站开发过程东莞长安网站设计公司
  • UVa 11183 Teen Girl Squad
  • 医疗教育的网站建设山西公司网站建设