【Java】 大話數據結構(14) 排序算法(1) (冒泡排序及其優化)

本文根據《大話數據結構》一書,實現了Java版的冒泡排序html

更多:數據結構與算法合集java

基本概念

  基本思想:將相鄰的元素兩兩比較,根據大小關係交換位置,直到完成排序。算法

  對n個數組成的無序數列,進行n輪排序,每輪按兩兩比較的方法找出最小(或最大)的一個。下圖表示某數列的第一輪排序。數組

下面爲交換元素的swap()方法代碼,後面代碼中將直接使用。數據結構

	public void swap(int[] a, int i, int j) {
		int temp;
		temp = a[j];
		a[j] = a[i];
		a[i] = temp;
	}

  

 

初級版本

根據基本思想,能夠寫出初級版本的冒泡排序以下:ide

	public void bubbleSort0(int[] a) {
		if(a==null) return;
		// 表明第i輪排序
		for (int i = 0; i < a.length; i++) {
			for (int j = a.length - 1; j > i; j--) {
				if (a[j] < a[j - 1]) {
					swap(a, i, j);
				}
			}
		}
	}

    

第一次優化版本

  當數據基本有序時,可能前幾輪循環就完成了排序,後面的循環就沒有必要繼續進行了,以下圖所示:post

  對這種狀況,能夠在代碼中增長一個標記,用於標記每輪循環時代碼是否已經有序,在每輪循環開始前,若是有序的話就沒有必要繼續進行比較了。具體Java代碼以下:測試

	public void bubbleSort1(int[] a) {
		if(a==null) return;
		boolean isSorted = false; // false表明數據無序,須要排序
		for (int i = 0; i < a.length && !isSorted; i++) { // 數據無序時還要繼續循環
			isSorted = true; // 假設這輪循環開始時已經有序
			for (int j = a.length - 1; j > i; j--) {
				if (a[j] < a[j - 1]) {
					swap(a, i, j);
					isSorted = false; // 有發生交換,說明這輪循環仍是無序的
				}
			}
		}
	}

    

第二次優化版本

  當數列的前半部分有序然後半部分無序時,每輪循環不必再對有序部分進行排序,例如,數列爲{1,2,3,4,9,5,8,7}時,在一次循環後知道1,2,3,4已經有序,後面的循環就不必對這些數字進行排序了。優化

  此時,關鍵點在於對有序區的界定:若是知道有序區的邊界,那麼每次循環就只須要比較到該邊界便可。在每次循環的最後,記錄下最後一次元素交換的位置,該位置就是有序區的邊界了。具體Java代碼以下:url

	public void bubbleSort2(int[] a) {
		if(a==null) return;
		int lastExchangeIndex = 0; // 用於記錄每輪循環最後一次交換的位置
		int sortBorder = 0; // 有序數組的邊界,每次比較只要比較到這裏就能夠
		boolean isSorted = false;
		for (int i = 0; i < a.length && !isSorted; i++) {
			isSorted = true;
			for (int j = a.length - 1; j > sortBorder; j--) {
				if (a[j] < a[j - 1]) {
					swap(a, i, j);
					isSorted = false;
					lastExchangeIndex = j; // 本輪最後一次交換位置(不斷更新)
				}
			}
			sortBorder = lastExchangeIndex; // 邊界更新爲最後一次交換位置
		}
	}

    

完整Java代碼

(含測試代碼)

import java.util.Arrays;

/**
 * 
 * @Description 冒泡排序(從小到大)
 *
 * @author yongh
 * @date 2018年9月13日 下午3:21:38
 */
public class BubbleSort {

	/**
	 * 初級版本
	 */
	public void bubbleSort0(int[] a) {
		if(a==null) return;
		// 表明第i輪排序
		for (int i = 0; i < a.length; i++) {
			for (int j = a.length - 1; j > i; j--) {
				if (a[j] < a[j - 1]) {
					swap(a, i, j);
				}
			}
		}
	}

	/**
	 * 優化版本
	 * 添加一個標記isSorted
	 */
	public void bubbleSort1(int[] a) {
		if(a==null) return;
		boolean isSorted = false; // false表明數據無序,須要排序
		for (int i = 0; i < a.length && !isSorted; i++) { // 數據無序時還要繼續循環
			isSorted = true; // 假設這輪循環開始時已經有序
			for (int j = a.length - 1; j > i; j--) {
				if (a[j] < a[j - 1]) {
					swap(a, i, j);
					isSorted = false; // 有發生交換,說明這輪循環仍是無序的
				}
			}
		}
	}

	/**
	 * 進一步優化版本
	 */
	public void bubbleSort2(int[] a) {
		if(a==null) return;
		int lastExchangeIndex = 0; // 用於記錄每輪循環最後一次交換的位置
		int sortBorder = 0; // 有序數組的邊界,每次比較只要比較到這裏就能夠
		boolean isSorted = false;
		for (int i = 0; i < a.length && !isSorted; i++) {
			isSorted = true;
			for (int j = a.length - 1; j > sortBorder; j--) {
				if (a[j] < a[j - 1]) {
					swap(a, i, j);
					isSorted = false;
					lastExchangeIndex = j; // 本輪最後一次交換位置(不斷更新)
				}
			}
			sortBorder = lastExchangeIndex; // 邊界更新爲最後一次交換位置
		}
	}
	
	/**
	 * 交換代碼
	 */
	public void swap(int[] a, int i, int j) {
		int temp;
		temp = a[j];
		a[j] = a[i];
		a[i] = temp;
	}
	
	//=========測試代碼=======
	public void test1() {
		int[] a = null;
		bubbleSort2(a);
		System.out.println(Arrays.toString(a));
	}


	public void test2() {
		int[] a = {};
		bubbleSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test3() {
		int[] a = { 1 };
		bubbleSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test4() {
		int[] a = { 3, 3, 3, 3, 3 };
		bubbleSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test5() {
		int[] a = { -3, 6, 3, 1, 3, 7, 5, 6, 2 };
		bubbleSort2(a);
		System.out.println(Arrays.toString(a));
	}
	
	
	public static void main(String[] args) {;
		BubbleSort demo = new BubbleSort();		
		demo.test1();
		demo.test2();
		demo.test3();
		demo.test4();
		demo.test5();
	}
}

    

null
[]
[1]
[3, 3, 3, 3, 3]
[3, 3, -3, 5, 2, 7, 1, 6, 6]
BubbleSort

 

總結

  冒泡排序原理近似於氣泡在水裏慢慢上浮到水面上,實現容易,但也有改進的空間,

  改進1:若前幾輪已經有序,則後面就不必繼續比較了,所以增長一個isSorted標記,對每輪是否有序進行標記。

  改進2:一部分有序,則不必繼續對有序區比較,增長一個sortBorder來定義有序區邊界,每次比較到該邊界便可。該邊界由每輪循環中最後一次元素交換的位置獲得。

   時間複雜度:O(n^2)

 

更多:數據結構與算法合集

相關文章
相關標籤/搜索