算法--排序--冒泡排序--JAVA

冒泡排序有多種不同的寫法,其中主要的區別就是性能的不同

這篇文章將逐步改進冒泡排序,使得冒泡排序不斷進化

原始人

先看代碼


	public void getSortArray(int array[]) {	
		int temp = 0; 
		for (int i = 0; i < array.length - 1; i++) {
			for (int j = 0; j < array.length - i - 1; j++) {
				if (array[j] > array[j + 1]) { 
					temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
				}
			}
		}
	}

原始人的代碼就是簡單 ,簡單看看就能看的差不多,這裏面有一個很重要的地方:i 與 j 的取值問題

我當時看到代碼時不僅要問,i 與 j 爲什麼要這樣取值呢?

答曰:

  • 對於 i 的 取值 :冒泡排序的目的就是 通過每次的交換,將最大的值交換到一串數字的最後,因爲 i 是最外層循環的控制變量,因此 i 就代表着循環的次數,假設外層循環了3次 ,那麼這串數字的最後3個數就已經有序了。所以,如果這串數字長度爲 n ,那麼顯然外層只要循環 n - 1 次就使得數列有序了。因此外層循環次數爲 array.length -1 次。

  • 對於 j 的取值:n 次外層循環使得數列最後 n 個爲有序而且有序區的每個數必然比前面的都大,因此在每次的內層循環,沒有必要再讓 j 從 0 --> array.length - 1,只要從 0 --> array.length - i - 1

原始人進化

先看代碼

	public void secondSortArray(int array[]) {
		int temp = 0;
		boolean sorted = false;
		for (int i = 0; i < array.length - 1; i++) {
			sorted = false;
			for (int j = 0; j < array.length - i - 1; j++) {
				if (array[j] > array[j + 1]) {
					temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
					sorted = true; 
				}
			}
			if(sorted == false) {
				break;
			}
		}
	}

最重要的就是添加了 sorted 這個布爾變量

爲什麼要添加這個變量呢?

看一個數列:1 2 3 4 5 8 7 顯然這個序列只通過一次就可以有序,但是實際上要經過 21 次循環

  • 求冒泡排序(原始人階段) 的計算公式:n(n-1)/ 2 其中 n 爲數列的長度

這顯然太耗費時間了,加上一個布爾變量,如果一次內部循環沒有經過變量交換,那麼就說明已經排序完成了,因此就結束排序。

原始人再進化

看代碼

	public void thirdSortArray(int array[]) {
		int temp = 0;
		int count = 0;
		int boundary = array.length - 1;
		boolean sorted = false;
		for (int i = 0; i < array.length - 1; i++) {
			sorted = false;
			for (int j = 0; j < boundary; j++) {
				count++;
				if (array[j] > array[j + 1]) {
					temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
					sorted = true;
					boundary = j;
				}
			}

			if (sorted == false) {
				break;
			}
		}
	}

例如 2 1 3 5 6 7 8 這個數列,如果讓我們人來進行排序,那麼你會怎麼做?我們會找一個邊界,這個邊界的右側都是比左側大的數而且已經有序,此後就只看這個邊界左側的數字。

那麼把這個事情交給程序呢?我們也需要讓程序找到這個邊界,這個邊界找到了,那麼此後程序再進行數字比較的時候就更加省時省力。

如何讓程序找到這個邊界?重中之重就是:找到最後一次進行兩數字交換的位置,這個位置就是邊界!

知道了這裏,那麼代碼也就很好看懂了(代碼引進了第一次進化)

爲了說明三者之間效率的差距,在內層循環設置一個變量count 計算整個排序過程的執行次數

	public void firstSortArray(int array[]) {
		int temp = 0;
		int count = 0;
		for (int i = 0; i < array.length - 1; i++) {
			for (int j = 0; j < array.length - i - 1; j++) {
				count++;
				if (array[j] > array[j + 1]) {

					temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
				}
			}
		}
		System.out.println("執行次數:"+count);
	}

另外兩個的代碼我就不貼了

對[ 2, 1, 3, 4, 5,6] 這個數組進行排序,得到結果分別爲:

執行次數:15
最終結果:123456
執行次數:9
最終結果:123456
執行次數:5
最終結果:123456

可以看到,效率差距還是很明顯的

詳細代碼:https://github.com/kai123wen/SUANFA/tree/master/%E6%8E%92%E5%BA%8F/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章