基本思想
冒泡排序的基本思想是:
通過對待排序的序列從前向后依次比較相鄰元素的值,如果發現逆序則交換。
逆序的含義:如果想把序列從小到大排序,那么兩個數中前面的比后面的大就是逆序。
若需求是將序列從小到大排序,那么每一趟比較都會把值較大的逐漸從前面移動到后面。
就像水底的泡泡一樣:
(如下圖,圖片來源於網絡)
例子
給定一個數組如下:
[ 5 , 8 , -2 , 20 -6 ]
定義兩個變量 i 和 j,初始狀態 i 存第一個元素的索引,j存i代表元素的下一個元素的索引;
如下圖:
第一趟排序
(1) 5 < 8不用發生交換
然后 i ,j 均向后移動;
(2) 8 > -2 需要發生交換
然后 i ,j 均向后移動;
(3) 8 < 20 不需要發生交換
然后 i ,j 均向后移動;
(4) 20 > -6 需要發生交換
此時 j已經不能向后移動,第一趟排序結束,將當前最大的元素 20 移動到了最后的位置。
第二趟排序
將 i ,j重新賦值如下:
第三趟排序
將 i ,j重新賦值如下:
第四趟排序
將 i ,j重新賦值如下:
四個數組均到達該到的位置,排序完畢。
由此可見,每一趟排序都會減少比較次數。
會 有數組長度-1趟排序。
代碼
使用雙重循環來完成:
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;
}
}
}
優化
如果一趟排序都沒有發生交換,表示已經有序了,沒必要進行接下來的排序了。
可以定義一個 flag ,初始值為false,如果發生交換,就賦值為true,否則一直是false直接退出循環。
代碼如下:
import java.lang.reflect.Array;
import java.util.Arrays;
public class Solution {
public static void main(String[] args) {
bubbleSort(new int[]{5,8,-2,20,-6});
}
public static void bubbleSort(int[] arr) {
int temp;//用於交換的臨時變量
boolean flag = false;//表示是否進行交換
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]){
flag = true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if(!flag){
break;
}else{
flag = false;//將flag重新置為false
}
}
System.out.println(Arrays.toString(arr));
}
}
時間復雜度
如果原數組有序,則遍歷一遍就可以,最好的時間復雜度是
$O(n)$;
如果原數組倒序,則比較次數是:
n-1 + n-2 + … + 2 + 1 = $\frac{n(n-1)}{2}$ = $O(n^2)$;
所以冒泡排序的時間復雜度是$O(n^2)$。
穩定性
冒泡排序就是把逆序的元素進行交換,每次都是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個元素相等,是不會再交換的;如果兩個相等的元素沒有相鄰,那么即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前后順序並沒有改變,所以冒泡排序是一種穩定排序算法。
總結
冒泡排序的思想是通過對待排序的序列從前向后依次比較相鄰元素的值,如果發現逆序則交換。
優化方法是,若一趟排序中沒有發生交換則退出循環,已經有序。
冒泡排序的時間復雜度是$O(n^2)$,是穩定的排序算法。
歡迎關注
歡迎大家的關注
掃描下方的二維碼關注我的微信公眾號:code隨筆