排序算法(一)冒泡排序

0. 簡介
  • 對於任一長度大於 1 的數組例如 ‘ int[] array = { 5, 4, 3, 2, 1};’ ,冒泡排序從數組的任意一端開始,向該數組的另一端傳遞(冒泡)最大(或最小)值,相鄰元素之間可能需要互相交換位置,以便將相對最大(或最小)的‘泡泡’冒出去。注意每一次冒泡都是從一個固定的端點(數組的頭或尾)開始,而每一次冒泡完成時,都可以確定一個元素的位置,對於有 n 個元素的數組,當確定了 n-1 個元素的位置時,這個數組便完成了排序工作。所以長度爲 n 的數組,需要冒泡 n-1 次。假設從數組( ‘ int[] array;’ )頭部開始冒泡:
    第 1 次冒泡:數組的第 1 個元素 array[0] 需要和其後面的 n-1 個元素進行比較,直到和最後一個元素 array[n-1]比較結束,便確定了第一個相對最大值,並將該值存放在下標爲 n-1 的位置即數組末端。
    第 2 次冒泡:數組的第 1 個元素 array[0] 需要和其後面的 n-2 個元素進行比較,直到和元素 array[n-2]比較結束,便確定了第 2 個相對最大值,並將該值存放在下標爲 n-2 的位置。
    第 n-1 次冒泡:數組的第 1 個元素 array[0]需要和其後面的 1 個元素進行比較,從而確定了第 n-1 個相對最大值,並將該值存放在下標爲 1 的位置。至此已經確定了 n-1 個元素的位置,排序完成。
    一個冒泡排序的例子,圖示過程如下:
    一個冒泡排序的例子冒泡是一個很形象的比喻,一個個氣泡接連冒出來。
    綜上,理一下冒泡排序法
    1. 對於長度爲 n 的數組
    2. 需要執行冒泡操作的次數爲 (n - 1)次,即最外層 for 循環的次數,因爲,每一次冒泡操作都可以確定一個相對最大(或最小)值,當確認了(n - 1)個相對最大(或最小)值時,剩下的最後一個元素一定是整個數組中最小(或最大)的值,整個數組即被確定爲遞增(或遞減),此時,排序完成。
    3. 對於第 1 次冒泡操作,數組的第 1 個元素和其它的(n - 1)個元素進行比較,以確定一個相對最大(或最小)值。當第一次冒泡操作完成,此時還剩下(n - 1)個元素需要進行排序,於是對這個(n - 1)個元素再次執行冒泡操作。直到完成第(n - 1)次冒泡操作(即 確定了 n-1 個相對最大或最小值),排序完成,因爲此時還剩下最後 1 = (n - (n - 1)) 個元素,它就呆在自己的位置,沒有‘人’和它爭論大小了。
    4. ‘冒泡的次數’ 與 ‘進行比較操作的次數’ 之間的關係。首先,對於在 x 個數中找一個最大(或最小)數的情況,方法是,先拿起任意一個數,然後依次與其它的每一個數(總共 x - 1 個,手裏的那個排除)進行比較操作,並用每次比較操作中最大(或最小)的數替換當前手中的數,這樣當所有比較操作執行完畢,手裏握着的便是最大(或最小)的數了。當第 m 次冒泡時,說明已有(m - 1)個相對最大(或最小)值已經確定了,所以,第 m 次冒泡是在(n - (m - 1))個元素中確定最大(或最小)值,對應的比較操作執行的次數則爲 ((n - (m - 1))- 1 )次。綜述,第 m 次冒泡,執行比較操作的次數即爲 ((n - (m - 1))- 1 )次。例如,第 1 次冒泡,使用上述公式則比較操作的次數爲 (n - 1)次,而第 (n - 1)次冒泡,使用上述公式則比較操作的次數爲 ((n - ((n - 1)- 1))- 1 )= 1 次(使用 n - 1 替換公式 ‘((n - (m - 1))- 1 )’ 中的 m 值)。(注意:每次執行冒泡操作時,在進行比較操作之前,手裏拿的一般是 array[0] 元素,即一般從數組頭部開始冒泡操作)
1.0 冒泡排序程序示例
/**
	 * 冒泡排序
	 * @param array 等待被排序的數組
	 * @param type 指定排序方式,小於 0:表示遞減排序,否則爲遞增排序
	 */
	public static void doSorting2(int[] array, int type) {
		int len = 0;
		int temp = 0;
		if (array != null && (len = array.length) > 1) {
			// 小於 0:表示遞減排序,否則爲遞增排序
			type = type > 0 ? 1 : -1;
			for(int i = 1;i < len;i++) {
				// (len - i) = (len - (i -1) - 1),
				// 即:排序次數 = (數組長度 - 已排序的元素個數即‘i - 1’ - 當前手裏拿着的 1 個元素)= (數組長度 - i)
				// 注意:j 的值從 0 開始,所以 ’j < len - i‘ 可以保證循環 ’len - i‘ 次
				for(int j = 0;j < len - i;j++) {
					if (type >= 0) {
						// 遞增排序
						if (array[j] > array[j + 1]) {
							temp = array[j];
							array[j] = array[j + 1];
							array[j + 1] = temp;
						}
					}else {
						// type < 0
						// 遞減排序						
						if (array[j] < array[j + 1]) {
							temp = array[j];
							array[j] = array[j + 1];
							array[j + 1] = temp;
						}
					}
				}
			}
		}
	}
2. 冒泡排序的性能
  1. 對於長度爲 n 的數組
  2. 第 1 次冒泡,執行比較操作的次數爲 n - 1
  3. 第 2 次冒泡,執行比較操作的次數爲 n - 2
  4. 第 3 次冒泡,執行比較操作的次數爲 n - 3
  5. .
  6. 最後一次即 n - 1 次冒泡,執行比較操作的次數爲 n - (n - 1) = 1 次
  7. 綜上,對長度爲 n 的數組排序,需要執行 n - 1 次冒泡操作,共計執行比較操作的次數爲:(n -1) + (n -2) + (n -3) + … + 2 + 1 即爲:(n - 1)*(n - 1 + 1) / 2 = (n - 1)*n / 2 ,這是一個 冪函數,隨着 n 的增大,執行比較操作的次數將急速增加。
  8. 函數圖形如下
    冪函數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章