Day26--冒泡排序
Day26--冒泡排序
冒泡排序无疑是最为出名的排序算法之一:总共有八大排序!
冒泡的代码还是相当简单的,两层循环:外层冒泡轮数,里层依次比较:江湖中人人尽皆知。
我们看到嵌套循环:应该立马就可以得出这个算法的时间复杂度为 O (n²)。思考:如何优化?
1. 冒泡排序的思路理解:
一、冒泡排序的起名由来:
冒泡排序的主要思想是通过多次遍历要排序的数列,每次比较相邻的两个元素,如果它们的顺序错误就把它们交换过来。
这样经过多次遍历,最大(或最小)的元素就会像气泡一样 “浮” 到数列的顶端。
二、具体过程
- 第一轮遍历:
- 从数列的第一个元素开始,依次比较相邻的两个元素。
- 如果前一个元素比后一个元素大,就交换它们的位置。
- 这样在第一轮遍历结束后,最大的元素就会被 “冒泡” 到数列的最后一个位置。
- 第二轮遍历:
- 由于最大的元素已经在最后位置,所以第二轮遍历只需要对前面的 n - 1 个元素进行操作。
- 重复第一轮的比较和交换过程,将第二大的元素 “冒泡” 到数列的倒数第二个位置。
- 依此类推:
- 每一轮遍历都将未排序部分中的最大元素 “冒泡” 到相应位置。
- 经过 n - 1 轮遍历后,整个数列就完成了排序。
三、示例说明
假设有一个整数数列 [8, 5, 2, 4, 3]。
-
第一轮遍历:
-
比较 8 和 5,因为 8 > 5,所以交换位置,数列变为 [5, 8, 2, 4, 3]。
-
比较 8 和 2,交换位置,变为 [5, 2, 8, 4, 3]。
-
比较 8 和 4,交换位置,变为 [5, 2, 4, 8, 3]。
-
比较 8 和 3,交换位置,变为 [5, 2, 4, 3, 8]。此时第一轮遍历结束,最大的元素 8 被 “冒泡” 到了最后位置。
-
-
第二轮遍历:
-
比较 5 和 2,交换位置,变为 [2, 5, 4, 3, 8]。
-
比较 5 和 4,交换位置,变为 [2, 4, 5, 3, 8]。
-
比较 5 和 3,交换位置,变为 [2, 4, 3, 5, 8]。第二轮结束,第二大的元素 5 被 “冒泡” 到了倒数第二个位置。
和第一轮相比,少了一次比较
-
-
第三轮遍历:
-
比较 2 和 4,不交换位置,数列仍为 [2, 4, 3, 5, 8]。
-
比较 4 和 3,交换位置,变为 [2, 3, 4, 5, 8]。第三轮结束,第三大的元素 4 被 “冒泡” 到了相应位置。
和第二轮相比,少了一次比较
-
-
第四轮遍历:
-
比较 2 和 3,不交换位置,数列保持 [2, 3, 4, 5, 8] 不变。第四轮结束,整个数列完成排序。
和第三轮相比,少了一次比较
-
四、具体分析
从第二轮遍历开始,每一轮遍历,都比上一轮少一次比较。
每一轮遍历,都会产生出一个最大或者最小的数,排在最前面或者最后面,因此比较次数少一次
遍历的轮数:array.length-1
五、时间复杂度
元素个数:n; 当前遍历轮数: i
时间复杂度:
- 最坏情况下,即数列是逆序的,需要进行 n - 1 轮遍历,每一轮遍历都要比较和交换 n - i 次(i 表示当前轮数),所以总的比较和交换次数为 n (n - 1)/2,时间复杂度为 O (n²)。
- 最好情况下,即数列已经是有序的,只需要进行一轮遍历就可以完成排序,时间复杂度为 O (n)。不过这种情况出现的概率较低。
-
时间复杂度的理解:以冒泡排序为例:
在计算机科学中,时间复杂度为 O (n²) 表示算法的运行时间与输入数据规模 n 的平方成正比。
具体来说,当输入数据规模为 n 时,算法的执行时间可以用一个包含 n² 的表达式来近似表示。例如,如果一个算法对于规模为 n 的输入数据需要执行 n² 次基本操作,那么这个算法的时间复杂度就是 O (n²)。
以冒泡排序为例,它有两层循环,外层循环执行 n - 1 次(n 为待排序数据的数量),内层循环在每一轮外层循环中执行的次数逐渐减少,但总体上也与 n 相关。对于一个包含 n 个元素的列表进行冒泡排序,大约需要比较和交换的次数为 n (n - 1)/2,当 n 很大时,这个数量级接近 n²,所以冒泡排序的时间复杂度为 O (n²)。
n (n - 1)/2的计算:
n-1+n-2+n-3+...+n-n=n*n-(1+2+...+n)=n *2 n/2-n (n + 1)/2=n/2 * (n-1)
2.冒泡排序的示例
从小到大排序
示例:数组a{1,3,2},进行从小到大排序
使用方法:1.用Arrays自带的方法
2.冒泡排序
package com.liu.www.array;
import java.util.Arrays;
public class ArrayDemo07 {
public static void main(String[] args) {
int[] a={1,3,2};
sort(a);
System.out.println(Arrays.toString(a));
}
//冒泡排序
//1. 比较两个相邻的元素大小。不行就交换位置,来满足:大的排后边,小的排前面
//2. 每一轮遍历,都会产生出一个最大或者最小的数
//3.下一轮可以少一次比较
//4.以此类推,直到结束
//下面的方法是从小往大排序
public static int[] sort(int[] array){
int temp=0;
//外层循环:判断循环的次数
for (int i = 0; i < array.length-1; i++) {
//内层循环:比较两个数的位置。如果第一个数比第二个数大,则交换位置
for (int j = 1; j <array.length-1-i; j++) {
if(array[j]>array[j+1]){
temp=array[j+1];
array[j+1]=array[j];
array[j]=temp;
}
}
}return array;
}
/*
1 4 2 3 arrays.length=4 i=0;i<3 j=0;j<3
1 4 1423 j=0;j<3
4 2---> 2 4 1243 j=1;j<3
4 3---> 3 4 1234 j=2;j<3
*/
}
优化:
当已经排好序的时候,就可以节省遍历次数了
//下面的方法是从小往大排序
public static int[] sort(int[] array){
int temp=0;
boolean flag=true;//通过flag标识符,减少没有意义的比较
//外层循环:判断循环的次数
for (int i = 0; i < array.length-1; i++) {
//内层循环:比较两个数的位置。如果第一个数比第二个数大,则交换位置
for (int j = 0; j <array.length-1-i; j++) {
if(array[j]>array[j+1]){
temp=array[j+1];
array[j+1]=array[j];
array[j]=temp;
flag=false;
}
if(flag==true){
break;
}
}
}return array;
}
通过flag标识符,减少没有意义的比较。
当内循环第一次循环结束之后,也就是第一轮遍历结束之后,如果第二轮一直都没有进入if执行语句,也就是array[j]<=array[j+1]一直成立,那么说明,排序完成,就可以跳出循环了。
错误示例1:
import java.util.Arrays;
public class Exercise2 {
public static void main(String[] args) {
int[] a={1,3,2};
System.out.println( Arrays.sort(a));
}
}
好的,下面来分析一下这段代码的错误以及如何改正:
错误分析
在你给出的代码中,Arrays.sort()
方法是用于对数组进行排序的,但它的返回值是void
,也就是它没有返回值。所以当你在System.out.println()
中直接调用Arrays.sort(a)
时,就会出错,因为System.out.println()
需要传入一个可以转换为字符串的值来进行输出,而void
类型显然不符合要求。
改正后的代码
要实现输出数组排序之后的结果,正确的做法是先对数组进行排序,然后再使用Arrays.toString()
方法将排序后的数组转换为字符串进行输出。以下是改正后的代码:
import java.util.Arrays;
public class Exercise2 {
public static void main(String[] args) {
int[] a = {1, 3, 2};
// 对数组a进行排序
Arrays.sort(a);
// 将排序后的数组转换为字符串并输出
System.out.println(Arrays.toString(a));
}
}
在上述改正后的代码中:
- 首先通过
Arrays.sort(a)
对整数数组a
进行排序操作,此时数组a
的元素顺序会被改变为升序排列(在Arrays.sort()
默认情况下是升序排序)。 - 然后使用
Arrays.toString()
方法将排序后的数组a
转换为一个字符串表示形式,这个字符串会以[
开始,以]
结尾,数组元素之间用逗号和空格分隔,比如如果数组排序后是[1, 2, 3]
,那么Arrays.toString(a)
返回的字符串就是[1, 2, 3]
。 - 最后通过
System.out.println()
将这个表示排序后数组的字符串输出到控制台,这样就实现了输出数组排序之后的结果的需求。
错误示例2:
import java.util.Arrays;
public class Exercise2 {
public static void main(String[] args) {
int[] a={1,3,2};
Arrays.sort(a);
System.out.println(a.toString());
}
}
分析:
以下是对这段代码错误原因的分析:
数组对象直接调用toString
方法的问题
在Java中,数组是一种特殊的对象类型。当你直接对数组对象(如这里的a
)调用toString
方法时,它并不会按照你期望的那样返回数组元素的内容。实际上,数组对象的toString
方法默认返回的是数组的一个哈希码表示形式(类似[I@10f87f48
这种格式),而不是数组中各个元素的值以某种可读的形式呈现出来。
正确的做法
要想正确输出已经排序好的数组的元素内容,应该使用Arrays.toString
方法。就像下面这样修改代码:
import java.util.Arrays;
public class Exercise2 {
public static void main(String[] args) {
int[] a = {1, 3, 2};
Arrays.sort(a);
// 使用Arrays.toString方法来获取数组元素内容的字符串表示并输出
System.out.println(Arrays.toString(a));
}
}
在修改后的代码中,Arrays.toString(a)
会遍历已经排序好的数组a
的每个元素,将它们转换为字符串形式,并按照[
开头、元素之间用逗号和空格分隔、]
结尾的格式生成一个新的字符串,然后通过System.out.println
输出这个字符串,这样就能正确展示出排序后数组的元素情况了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端