冒泡排序

本文首發於我的博客html

前言

本系列排序包括十大經典排序算法。git

  • 使用的語言爲:Java
  • 結構爲: 定義抽象類Sort裏面實現了,交換,大小比較等方法。例如交換兩個值,直接傳入下標就能夠了。其餘的具體排序的類都繼承抽象類Sort。這樣咱們就能專一於算法自己。
/*
	 * 返回值等於0,表明 array[i1] == array[i2]
	 * 返回值小於0,表明 array[i1] < array[i2]
	 * 返回值大於0,表明 array[i1] > array[i2]
	 */
	protected int cmp(int i1, int i2) {
		return array[i1].compareTo(array[i2]);
	}
	
	protected int cmp(T v1, T v2) {
		return v1.compareTo(v2);
	}
	
	protected void swap(int i1, int i2) {
		T tmp = array[i1];
		array[i1] = array[i2];
		array[i2] = tmp;
	}

複製代碼

什麼是冒泡排序

  • 冒泡排序(Bubble Sort)是一種計算機科學領域的較簡單的排序算法。
  • 它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,若是他們的順序(如從大到小、首字母從A到Z)錯誤就把他們交換過來。走訪元素的工做是重複地進行直到沒有相鄰元素須要交換,也就是說該元素列已經排序完成。
  • 這個算法的名字由來是由於越大的元素會經由交換慢慢「浮」到數列的頂端(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端同樣,故名「冒泡排序」。

算法原理

  • 比較相鄰的元素。若是第一個比第二個大,就交換他們兩個。
  • 對每一對相鄰元素作一樣的工做,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
  • 針對全部的元素重複以上的步驟,除了最後一個。
  • 持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。

算法分析

時間複雜度

  • 若文件的初始狀態是正序的,一趟掃描便可完成排序。所需的關鍵字比較次數C和記錄移動次數M 均達到最小值:C=n-1 , M=0。
  • 因此,冒泡排序最好的時間複雜度爲O(n) 。
  • 若初始文件是反序的,須要進行 n-1 趟排序。每趟排序要進行 n-i 次關鍵字的比較(1≤i≤n-1),且每次比較都必須移動記錄三次來達到交換記錄位置。在這種狀況下,比較和移動次數均達到最大值: C = n(n-1)/2 = O(n^2). M = 3n(n-1)/2 = O(n^2).

冒泡排序的最壞時間複雜度爲 O(n^2)。 綜上,所以冒泡排序總的平均時間複雜度爲O(n^2)。github

算法穩定性

  • 冒泡排序就是把小的元素往前調或者把大的元素日後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。因此,若是兩個元素相等,是不會再交換的;若是兩個相等的元素沒有相鄰,那麼即便經過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,因此相同元素的先後順序並無改變,因此冒泡排序是一種穩定排序算法。

是不是原地算法

  • 何爲原地算法?
    • 不依賴額外的資源或者依賴少數的額外資源,僅依靠輸出來覆蓋輸入
    • 空間複雜度爲 𝑂(1) 的均可以認爲是原地算法
  • 非原地算法,稱爲 Not-in-place 或者 Out-of-place
  • 冒泡排序屬於 In-place

代碼

代碼一

public class BubbleSort<T extends Comparable<T>> extends Sort<T>  {

	@Override
	protected void sort() {
		for (int end = array.length-1; end>0; end--) {
			for (int begin = 1; begin <= end; begin++) {
				if (cmp(begin, begin-1)<0) {
				//ayyay[begin] 小於 ayyay[begin-1] 就交換
					swap(begin, begin-1);
				}
			}
		}
	}
}

複製代碼

優化

  • 咱們知道,每次都是兩兩比較,若是已經拍好順序了。能夠提早終止排序
public class BubbleSort1<T extends Comparable<T>> extends Sort<T>  {

	@Override
	protected void sort() {
		// TODO Auto-generated method stub
		for (int end = array.length-1; end >0; end--) {
			boolean isSorted = true; //定義布爾值 isSorted來標記是否有交換
			for (int begin = 1; begin <= end; begin++) {
				//ayyay[begin] 小於 ayyay[begin-1] 就交換
				if (cmp(begin, begin-1)<0) {
					swap(begin, begin-1);
					isSorted = false;
				}
			}
			if (isSorted) {
				//來到這裏,說明沒有交換過。已是徹底有序的了。提早終止排序
				break;
			}
			
		}
	}

}

複製代碼

再次優化

  • 若是序列尾部已經局部有序,能夠記錄最後1次交換的位置,減小比較次數
public class BubbleSort2<T extends Comparable<T>> extends Sort<T>   {

	@Override
	protected void sort() {
		// TODO Auto-generated method stub
		for (int end = array.length-1; end >0; end--) {
			int sortedIndex = 1;
			for (int begin = 1; begin <= end; begin++) {
				if (cmp(begin, begin-1)<0) {
					swap(begin, begin-1);
					sortedIndex = begin;
				}
			}
			end = sortedIndex;
			
		}
	}

}

複製代碼

驗證

使用數據源以下算法

Integer[] array = {7, 3, 5, 8, 6, 7, 4, 5,19,30,40,50};bash

結果爲:ide

  • 【BubbleSort】 穩定性:true 耗時:0.0s(0ms) 比較次數:66 交換次數:14測試

  • 【BubbleSort1】穩定性:true 耗時:0.001s(1ms) 比較次數:51 交換次數:14優化

  • 【BubbleSort2】穩定性:true 耗時:0.0s(0ms) 比較次數:30 交換次數:14ui

能夠明顯感受到作了優化以後,比較測試減小了。spa

代碼地址:

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息