一、基本思路
基本思路: 将待排序序列从前向后扫描,依次比较相邻的元素,若发现相邻元素逆序,则交换位置,直到没有相邻的元素需要交换。
简单来说: 就是依次找出待排序列中较大的元素放在序列较后的位置。
举例:
有一序列为:2,7,-2,18,9要求按升序排列
先从左往右遍历,并且依次比较相邻的元素,如果是逆序就交换。
- 第一趟比较(比较前n个元素,5个元素比较4次)
(1)2,7,-2,18,9 //2和7比较,不是逆序不交换
(2)2,-2,7,18,9 //7和-2比较,是逆序就交换
(3)2,-2,7,18,9 //7和18比较,不是逆序不交换
(4)2,-2,7,9,18 //18和9比较,是逆序就交换
2.第二趟比较(比较前n-1个元素,最大的元素18位置已经固定,不用比较,4个元素比较3次)
(1)-2,2,7,9,18 //2和-2比较,是逆序就交换
(2)-2,2,7,9,18 //2和7比较,不是逆序不交换
(3)-2,2,7,9,18 //7和9比较,不是逆序不交换
3.第三趟比较(比较前n-2个元素,18和9位置已经固定,3个元素比较2次)
(1)-2,2,7,9,18 //-2和2比较,不是逆序不交换
(2)-2,2,7,9,18 //2和7比较,不是逆序不交换
此时发现第三趟中没有元素发生交换,即已经得到一个升序排列,所以在此处可以退出并输出结果。
二、算法分析
时间: 通过思路分析发现,冒泡排序需要依次比较两个相邻的元素,若有待排序列中有n个元素,就需要比较n个元素的大小,需要比较n-1次,最坏情况下,如果所有元素都要交换,则需要n-1趟,最好情况下,若待排序列就是规定序列,则需要1趟。
空间: 冒泡排序只需要在给定的序列内进行排序,无需另外开辟空间。
算法 | 平均时间 | 最好情形 | 最坏情形 | 稳定度 | 空间复杂度 | 备注 |
---|---|---|---|---|---|---|
冒泡排序 | O(n²) | O(n) | O(n²) | 稳定 | O(1) | n小时较好 |
三、代码实现
下面简单对随机情况、最好情况、最坏情况都进行了一个测试。
import java.util.Arrays;
/**
* @author dankejun
* @create 2020-04-24 21:15
*/
public class BubbleSort {
public static void main(String[] args) {
// int arr[] = {3, 9, -1, 10, 20,-2};
// int arr[] = {1,2,3,4,5,6};//最好情况
// int arr[] = {6,5,4,3,2,1};//最坏情况
int arr[] = {2,7,-2,18,9};
bubbleSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void bubbleSort(int[] arr) {
int temp ;//临时变量
boolean flag = false;//标志变量,若存在交换置flag为true,否则为false
for (int k = 0; k < arr.length - 1; k++) {//趟数,n个数最多比较n-1趟
for (int i = 0; i < arr.length - 1 - k; i++) {//比较相邻元素
if (arr[i] > arr[i + 1]) {
flag = true;//发生交换
temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
System.out.printf("第%d趟排序结果:%s\n",k+1, Arrays.toString(arr));
if (!flag) {//一趟中无发生交换的元素
break;
} else {//一趟中存在发生交换的元素
flag = false;//重置交换标志
}
}
}
}
通常随机情况:(上面思路分析中的例子,遍历趟数小于等于n-1)
测试序列: int arr[] = {2,7,-2,18,9};
测试结果:
最好情况下:(本来就是升序)
测试序列: int arr[] = {1,2,3,4,5,6};
测试结果:只需要一趟
最坏情况下:(元素每趟都需要进行交换)
测试序列:int arr[] = {6,5,4,3,2,1};
测试结果:需要n-1趟(n为元素数量)