內容介紹
冒泡排序原理
冒泡排序(Bubble Sort)是一種交換排序,它的基本思想是:兩兩比較相鄰的數據,大的日後放。java
你們必定看過水中的氣泡,小氣泡一點一點向上浮動變成大氣泡。 算法
冒泡排序這個算法的名字由來是由於元素像水中的氣泡冒泡同樣,小的元素會通過交換慢慢「浮」到數列的一端。咱們來看冒泡排序的動畫演示。 編程
冒泡排序的分析
通常沒有特殊要求排序算法都是升序排序,小的在前,大的在後。數組由{6, 5, 4, 1, 3, 2}這6個無序元素組成。數組
冒泡排序交換過程圖示(第一輪): 微信
第一次相鄰的元素6和元素5比較,發現前面的元素大於後面的元素,交換位置。 優化
交換後 動畫
第二次相鄰的元素6和元素4比較,發現前面的元素大於後面的元素,交換位置。 code
交換後 blog
第三次相鄰的元素6和元素1比較,發現前面的元素大於後面的元素,交換位置。 排序
交換後
第四次相鄰的元素6和元素3比較,發現前面的元素大於後面的元素,交換位置。
交換後
第五次相鄰的元素6和元素2比較,發現前面的元素大於後面的元素,交換位置。
交換後
通過第一輪的五次比較,元素6由數組的最前面冒泡到數組的最後面。最大的元素就在數組的最後面。注意觀察,通過一輪比較只能將參數比較的數字中的最大的數字冒泡到右邊,其他的仍是無序的。所以須要進行多輪比較才能將數組變成有序的。
冒泡排序交換過程圖示(第二輪):
通過第二輪的四次比較,元素5由數組的最前面冒泡到數組的倒數第二的位置。大的元素就在數組的後面。數組最後面的元素5和元素6能夠比較也能夠不比較,對結果沒有影響。到時候咱們寫代碼的時候注意一下便可。
冒泡排序交換過程圖示(第三輪):
交換過程和前兩輪分析的相似,咱們省略過程,最終第三輪交換後的結果:
冒泡排序交換過程圖示(第四輪):
交換過程和前兩輪分析的相似,咱們省略過程,最終第四輪交換後的結果:
冒泡排序交換過程圖示(第五輪):
第五輪比價元素1和元素2,這兩個元素自己已經有序了,因此沒有變化,最終第五輪交換後的結果和第四輪同樣:
到此爲止,全部元素都是有序的了,這就是冒泡排序的總體過程。
冒泡排序代碼編寫
咱們發現每一輪都須要從索引0開始,相鄰元素兩比較,須要使用一個循環(內循環)控制每輪的比較元素。另外數組6個元素須要通過五輪比較,也須要使用一個循環(外循環)控制比較的輪數,並且比較的輪數是元素的數量-1。
public class BubbleSortTest { public static void main(String[] args) { int[] arr = new int[]{6, 5, 4, 1, 3, 2}; System.out.println("排序前數組" + Arrays.toString(arr)); bubbleSort1(arr); } // 冒泡排序 public static void bubbleSort1(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { // 外循環控制比較的輪數,輪數是元素的數量-1 for (int j = 0; j < arr.length - 1 - i; j++) { // 內循環控制每輪比較的元素,輪數越大,比較的次數越少 if (arr[j] > arr[j+1]) { // i和i+1索引比較,也就是相鄰元素比較,大的日後放 System.out.print("\t元素 " + arr[j] + " 和 " + arr[j+1] + " 比較, "); int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; System.out.println("比較後" + Arrays.toString(arr)); } } System.out.println("排序" + (i+1) + "輪後: " + Arrays.toString(arr)); } } }
運行效果以下:
排序前數組[6, 5, 4, 1, 3, 2] 元素 6 和 5 比較, 比較後[5, 6, 4, 1, 3, 2] 元素 6 和 4 比較, 比較後[5, 4, 6, 1, 3, 2] 元素 6 和 1 比較, 比較後[5, 4, 1, 6, 3, 2] 元素 6 和 3 比較, 比較後[5, 4, 1, 3, 6, 2] 元素 6 和 2 比較, 比較後[5, 4, 1, 3, 2, 6] 排序1輪後: [5, 4, 1, 3, 2, 6] 元素 5 和 4 比較, 比較後[4, 5, 1, 3, 2, 6] 元素 5 和 1 比較, 比較後[4, 1, 5, 3, 2, 6] 元素 5 和 3 比較, 比較後[4, 1, 3, 5, 2, 6] 元素 5 和 2 比較, 比較後[4, 1, 3, 2, 5, 6] 排序2輪後: [4, 1, 3, 2, 5, 6] 元素 4 和 1 比較, 比較後[1, 4, 3, 2, 5, 6] 元素 4 和 3 比較, 比較後[1, 3, 4, 2, 5, 6] 元素 4 和 2 比較, 比較後[1, 3, 2, 4, 5, 6] 排序3輪後: [1, 3, 2, 4, 5, 6] 元素 3 和 2 比較, 比較後[1, 2, 3, 4, 5, 6] 排序4輪後: [1, 2, 3, 4, 5, 6] 排序5輪後: [1, 2, 3, 4, 5, 6]
這是最原始的冒泡排序,該排序算法的每一輪要遍歷全部元素,而且輪數和元素數量只少1,時間複雜度: 最優時間複雜度:O(n^2) (即便元素有序仍是須要進行比較) 最壞時間複雜度:O(n^2) 穩定性:穩定
這個算法的效率是很是低的。
冒泡排序代碼優化1
優化1: 若是有一輪發現沒有須要排序的,說明已經有序了,能夠不用再遍歷比較了。以下圖所示,第一輪比較事後,第二輪比較時發現元素已經所有是有序的,直接退出就沒有必要再進行後面第三,第四,五輪的比較了。
代碼以下:
public class BubbleSortTest2 { public static void main(String[] args) { int[] arr = new int[]{1, 3, 2, 4, 5, 6}; System.out.println("排序前數組" + Arrays.toString(arr)); bubbleSort2(arr); } // 優化1:若是有一輪發現沒有須要排序的,說明已經有序了.能夠不用再遍歷比較了 public static void bubbleSort2(int[] arr) { // 0.132s for (int i = 0; i < arr.length - 1; i++) { boolean sorted = true; // 用於標記數組是否有序,若是這輪一個元素都沒有交換說明有序,後面幾輪不須要在排序了 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; sorted = false; // 有元素須要交換,說明數組仍是無序的. } } if (sorted) { System.out.println("已經有序了, length = " + arr.length + ", 第 " + (i+1) + "輪"); break; } } } }
運行效果以下:
排序前數組[1, 3, 2, 4, 5, 6] 已經有序了, length = 6, 第 2輪
利用布爾變量sorted做爲標記。若是在本輪排序中,沒有元素交換,說明數組已經有序,直接跳出大循環。通過此次優化後,若是數組已經有順序了,能夠減小比較的輪數。
冒泡排序代碼優化2
優化2: 問題是在於j<array.length– i– 1。每輪都會比較到array.length– i– 1這個位置,若是後面已是有序的就不須要比較,下一輪只須要比較到上一輪的最後一次交換的小值那個地方便可,減小每輪的比較次數。
優化前第二輪須要比較到索引4的位置,優化後第二輪只須要比較到上次最後比較的那個位置,也就是lastPosition的位置
代碼以下:
public class BubbleSortTest2 { public static void main(String[] args) { int[] arr = new int[]{3, 2, 1, 4, 5, 6, 7}; System.out.println("排序前數組" + Arrays.toString(arr)); bubbleSort3(arr); } // 優化2:問題是在於j<array.length– i– 1。若是後面已是有序的就不須要比較 // 下一輪只須要比較到上一輪的最後一次交換的小值那個地方便可 public static void bubbleSort3(int[] arr) { // 0.132s int lastPosition = 0; // 記錄這一輪最後一次比較的較小那個值,下一輪就比較到這裏 int len = arr.length - 1; // len表示下一輪要比較到哪裏?後面會讓len = lastPosition for (int i = 0; i < arr.length - 1; i++) { boolean sorted = true; // 用於標記數組是否有序,若是這輪一個元素都沒有交換說明有序,後面幾輪不須要在排序了 for (int j = 0; j < len; j++) { if (arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; sorted = false; // 有元素須要交換,說明數組仍是無序的. lastPosition = j; // 記錄這一輪最後一次比較的較小那個值,下一輪就比較到這裏 } else { System.out.println("第 " + i + " 輪的第 " + j + " 次不須要交換"); } } len = lastPosition; if (sorted) { System.out.println("已經有序了, length = " + arr.length + ", i = " + i); break; } } } }
冒泡排序複雜度
這是最原始的冒泡排序,該排序算法的每一輪要遍歷全部元素,而且輪數和元素數量只少1,時間複雜度:
- 最優時間複雜度:O(n) 當數據自己已經有序如:{1, 2, 3, 4, 5, 6},咱們作了優化,比較一輪就結束。
- 最壞時間複雜度:O(n^2) 當數據自己是倒序的如:{6, 5, 4, 3, 2, 1},總執行次數爲n^2-n。
- 平均時間複雜度:O(n^2)。
- 穩定性:穩定
總結
冒泡排序是一種交換排序,它的基本思想是:兩兩比較相鄰的數據,大的日後放。使用嵌套循環來實現冒泡排序,外循環控制比較的輪數,內循環控制每輪比較的次數。 冒泡排序能夠進行兩個優化:
- 若是有一輪發現沒有須要排序的,說明已經有序了,能夠不用再遍歷比較了,減小比較輪數。
- 每輪都會比較到array.length– i– 1這個位置,若是後面已是有序的就不須要比較,下一輪只須要比較到上一輪的最後一次交換的小值那個地方便可,減小每輪的比較次數。
原創文章和動畫製做真心不易,您的點贊就是最大的支持! 想了解更多文章請關注微信公衆號:表哥動畫學編程