首先说明一下,此案例中的排序是基于数组升序排列。
原理:每次比较两个相邻的元素,将较大的元素交换至右端。
思路:
- 从头部开始比较相邻的两个元素,如果头部的元素比后面的大,就交换两个元素的位置;
- 往后对每个相邻的元素都做这样的比较、交换操作,这样到数组尾部时,最后一个元素会成为最大的元素;
- 重新从头部开始第 1、2 步的操作,除了在这之前尾部已经排好的元素;
- 继续对越来越少的数据进行比较、交换操作,直到没有可比较的数据为止,排序完成。
下面用代码实现一下:
public static void main(String[] args) {
// 定义数组长度
int arrLength = 10;
// 声明一个数组
int[] arr = new int[arrLength];
// 初始化数组
Random rand = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = rand.nextInt(50);
}
System.out.println("排序前数组: " + Arrays.toString(arr));
// 进行冒泡排序
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) { // 每次对相邻的两个元素进行比较
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println("排序后数组: " + Arrays.toString(arr));
}
运行结果:
排序前数组: [47, 3, 16, 35, 38, 1, 32, 47, 20, 24]
排序后数组: [1, 3, 16, 20, 24, 32, 35, 38, 47, 47]
可以看到,上面的代码已经成功实现冒泡排序了,但是这是最优的写法吗?想一下,如果这个数组本来就是有序的呢,或者通过前几次排序就已经有序了呢,按理说,这时只需一次或几次排序就可以知道数组是有序的了,如果按照上面的方法进行排序,很明显,后面的循环比较是毫无意义的,凭着这个思路,优化一下代码:
public static void main(String[] args) {
// 定义数组长度
int arrLength = 10;
// 声明一个数组
int[] arr = new int[arrLength];
// 初始化数组
Random rand = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = rand.nextInt(50);
}
System.out.println("排序前数组: " + Arrays.toString(arr));
// 进行冒泡排序
for (int i = 0; i < arr.length - 1; i++) {
boolean switchFlag = false; // 增加布尔变量,记录本次循环是否存在相邻元素的交换
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) { // 每次对相邻的两个元素进行比较
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
switchFlag = true;
}
}
if (!switchFlag) {// 如果本次循环不存在相邻元素交换,说明数组已经有序了
break;
}
}
System.out.println("排序后数组: " + Arrays.toString(arr));
}
冒泡排序最好的时间复杂度为O(n),最坏情况下时间复杂度为O(n^2^),平均时间复杂度为O(n^2^) 。