1、介绍
通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。
优化: 因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在 排序过程中设置一个标志 flag 判断元素是否进行过交换。从而减少不必要的比较。(这里说的优化,可以在冒泡排 序写好后,在进行)
2、算法分析
(1)比较相邻的元素。如果第一个比第二个大,就交换它们两个;
(2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
(3)针对所有的元素重复以上的步骤,除了已经排好顺序的;
(4)重复步骤1~3,直到排序完成。
(5)如果我们发现在某趟排序中,没有发生一次交换, 可以提前结束冒泡排序。这个就是优化
关于第二次优化,我实在一个公众号上看到的,作者景禹:
3、代码实现
package com.czq.algorithm;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* 冒泡排序
*
* @author czq
* @date 2020/07/16
*/
public class BubbleSort {
public static void main(String[] args) {
//测试排序的执行速度
//创建要给 8000000 个的随机的数组
int[] arr = new int[80000];
for (int i = 0; i < arr.length; i++) {
// 生成一个[0, 8000000) 数
arr[i] = (int) (Math.random() * 8000000);
}
// int arr[] = {8, 4, 5, 7, 1, 3, 6, 2};
System.out.println("============排序前===============");
// System.out.println("排序后:" + Arrays.toString(arr));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("排序前时间:" + sdf.format(new Date()));
bubbleSortOptimization2(arr);
System.out.println("============排序后===============");
System.out.println("排序前时间:" + sdf.format(new Date()));
// System.out.println("排序后:" + Arrays.toString(arr));
}
/**
* 冒泡排序
*
* @param arr 排序的原始数组
*/
private static void bubbleSort(int[] arr) {
// 临时变量
int temp;
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]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 冒泡排序一次优化,如果一趟比较下来没有进行过交换,就说明序列有序
*
* @param arr 排序的原始数组
*/
private static void bubbleSortOptimization(int[] arr) {
// 临时变量
int temp;
// 标识变量,表示是否进行过交换
boolean flag = false;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = true;
}
}
//判断元素是否进行过交换,没有则说明数组已经有序
if (!flag) {
break;
}
//重置 flag,进行下次判断
flag = false;
}
}
/**
* 冒泡排序二次优化,当一趟冒泡排序的过程中最后一次发生交换的位置为lastIndex,那么这个位置就是有序和无序部分的边界,它之后的数据是有序的
*
* @param arr 排序的原始数组
*/
private static void bubbleSortOptimization2(int[] arr) {
// 临时变量
int temp;
// 标识变量,表示是否进行过交换
boolean flag = false;
//记录最后一次交换的位置
int lastIndex = 0;
//将有序和无序部分的边界初始化为最后一个元素
int sortBorder = arr.length - 1;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < sortBorder; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = true;
lastIndex = j;
}
}
sortBorder = lastIndex;
//判断元素是否进行过交换,没有则说明数组已经有序
if (!flag) {
break;
}
//重置 flag,进行下次判断
flag = false;
}
}
}
结果:80000长度的数组排序时间需要10-12秒,时间复杂度O(n2),空间复杂度O(1)
800000长度的数组排序时间需要16-18分钟