一.什么是冒泡排序算法?
简单来说,就是将待排序的数据像水底冒泡一样,水泡从小逐渐变大,就像是有序【升序】的一样。冒泡排序原理与其非常相似,拿升序【数据从小到大】排列来说,把每个数据都比作一个气泡【有大有小】,一次冒出一个最大的气泡,直到将所有气泡全部冒完数据便是有序了。
二.冒泡排序(Bubble Sort)的基本思想
通过对待排序数据从前往后【从下标较小的元素开始】,依次比较相邻元素的值,假设要求数据按照升序排列,若发现前一个数据大于后一个,则将它们交换位置,使较大的元素逐渐从前向后移,就想水中的气泡一样逐渐向上冒。
三.冒泡排序的思路分析
假设现在有一个数组arr,元素个数为n个,对数组arr元素进行升序排列
1.一共冒泡n - 1次,也就是排序n-1趟
解释:比如有5个数据待排序,一趟排出1个最大值,排4趟就是4个,此时剩下的一个自然就是最小的,就不要进行后续排序了。
2.每排序一趟获得一个最大值,下一趟排序该最大值不参与
3.每趟需要比较【相邻元素比较】的次数都比上一趟少1次
解释:因为上一趟已经排出了1个最大值【不参与此趟比较】,所以此轮待排序的数据少1个,自然就要少比较1次。
冒泡排序步骤图解:
代码实现:
//冒泡排序 public void bubbleSort(int[] arr){ //嵌套for循环,外层循环表示趟数,内层循环表示每一趟需要比较的次数 for (int i = 0;i < arr.length - 1;i++){ //每趟比较次数递减1,而i刚好符合条件,所以-i for (int j = 0;j < arr.length - i - 1;j++){ if (arr[j] > arr[j+1]){//比较前一项比后一项大,就交换 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } }
三.时间复杂度
因为有嵌套for循环,所以冒泡排序的时间复杂度为O(n^2)
四.冒泡排序的优化
假设有一个数组arr = {6,1,2,3,4,5},现在使用冒泡排线对该数组进行升序排序,我们不难发现,只需要排序1趟该数组就有序了,那么后续几趟比较就是没有意义的,那么当某一趟数据已经有序了之后如何及时的终止排序呢?
我们可以在每趟排序前设置一个布尔类型的flag标志变量,初始化为true:
boolean flag = true;
在交换的代码中,我们加上flag = false这行代码,就像这样:
if (arr[j] > arr[j+1]){//前一项比后一项大,就交换 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; flag = false; }
如果一趟比较下来,没有进行交换的话,flag也不会被更新为false,说明此时数据已经有序了,此时对flag进行判断,为true就退出循环。
if (flag)//true表示没有进行交换,则数组已经有序 break;
优化过后的完整代码:
//冒泡排序【优化版】 public static void bubbleSort(int[] arr){ //嵌套for循环,外层循环表示趟数,内层循环表示每一趟需要比较的次数 for (int i = 0;i < arr.length - 1;i++){ boolean flag = true;//判断是否在某一趟就有序的标志 //每趟比较次数递减1,而i刚好符合条件,所以-i for (int j = 0;j < arr.length - i - 1;j++){ if (arr[j] > arr[j+1]){//比较前一项比后一项大,就交换 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; //进行了交换,说明此趟数组还没有有序,所以更新flag的值为false flag = false; } } //排完一趟就对flag的值进行判断,为true表示已经有序,此时退出循环 if (flag) break; } }