十大经典排序算法 ( 一 ) 冒泡排序
介绍 :
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
算法原理 :
-
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
-
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
动图演示 :
算法稳定性 :
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
时间复杂度 :
1.如果我们的数据正序,只需要走一趟即可完成排序。所需的比较次数 C 和记录移动次数 M 均达到最小值,即:Cmin=n-1 ; Mmin=0 ; 所以,冒泡排序最好的时间复杂度为 O(n) 。
2.如果很不幸我们的数据是反序的,则需要进行 n-1 趟排序。每趟排序要进行 n-i 次比较 ( 1 ≤ i ≤ n-1 ),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
综上所述:冒泡排序总的平均时间复杂度为:O(n2) ,时间复杂度和数据状况无关。
Java代码 :
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Arrays; /** * 冒泡排序 */ public class BubbleSort { private static Log log = LogFactory.getLog (BubbleSort.class); public static void main(String[] args) { int size = 10;// 数组长度(0 - 10) int value = 100;// 值大小(-100 - 100) int[] arr = generateRandomArray (size, value); // 对象拷贝:一维数组:深克隆(重新分配空间,并将元素复制过去) int[] bubbleArr = arr.clone (); int[] sortArr = arr.clone (); StringBuilder arrStr = new StringBuilder ("原数组: "); for (int number : arr) { arrStr.append (number).append (" "); } log.info (arrStr); bubbleSort (bubbleArr); StringBuilder bubbleStr = new StringBuilder ("冒泡排序:"); for (int bValue : bubbleArr) { bubbleStr.append (bValue).append (" "); } log.info (bubbleStr); // 绝对正确的方法,这个方法可以时间复杂度很差,但是要保证其准确性 Arrays.sort (sortArr);// 调用系统的函数来进行验证 StringBuilder sortStr = new StringBuilder ("系统函数排序: "); for (int sValue : sortArr) { sortStr.append (sValue).append (" "); } log.info (sortStr); log.info (isEqual (bubbleArr, sortArr) ? "成功" : "失败"); } private static boolean isEqual(int[] arr1, int[] arr2) { for (int i = 0; i < arr1.length; i++) { if (arr1[i] != arr2[i]) { return false; } } return true; } //N个数字冒泡排序,总共要进行N-1趟比较,每趟的排序次数为(N-i)次比较 private static void bubbleSort(int[] arr) { //判断边界条件 if (arr == null || arr.length < 2) { return; } log.info ("数组长度: " + arr.length + ", 预计执行" + (arr.length - 1) + "轮排序"); boolean flag = false;// 判断是否发生交换 for (int i = 0; i < arr.length - 1; i++) { log.info ("=========第" + (i+1) + "轮比较"); for (int j = 0; j < arr.length - i - 1; j++) { // 开始进行比较,如果arr[j]比arr[j+1]的值大,那就交换位置 if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; flag = true;// 发生交换 } StringBuilder sb = new StringBuilder (); sb.append ("第").append (j+1).append ("次比较:"); for (int number : arr) { sb.append (number).append (" "); } log.info (sb); } if (!flag) { log.info ("flag为false,未发生交换,数组有序,退出冒泡排序"); break; } flag = false; } } //生成一个对数器。产生一个随机样本的数组,数组的长度和值都是随机的 private static int[] generateRandomArray(int size, int value) { // 生成长度随机的数组,数组的最大长度是size的长度 int[] arr = new int[(int) ((size + 1) * Math.random ())]; for (int i = 0; i < arr.length; i++) { //针对数组中的每个值都可以随机一下,一个随机数减去另外一个随机数,可能产生正数,也可能产生负数 arr[i] = (int) ((value + 1) * Math.random ()) - (int) (value * Math.random ()); } return arr; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端