1. 程式人生 > >陣列排序(冒泡、快速)

陣列排序(冒泡、快速)

面試的時候總愛問排序,其實排序並不難,只是將一個排序的思路轉成程式語言實現。對於實際工作中,我們遇到的業務邏輯,要比排序的邏輯複雜的多,卻奇怪於有的公司總愛問這個,更奇怪的是,總有朋友答不上來。(說來慚愧,答不上來的人裡也包括我自己,不是不會寫,只是不知道什麼是快速排序)。這裡整理了下面兩個排序。

先來說說氣泡排序,氣泡排序就是將當前位置的數依次和後面位置的數比較,將大數放在前面,小數放在後面。

如:int[] arr = {3,2,6,4,1,5,8,9,7};排序完以後的結果:int[] arr = {9,8,7,6,5,4,3,2,1};

3和2比較,3在前面,不需要交換;3和6比較,6放前面;6和4比較,6放前面;。。。如此繼續比較下去。

下面看看程式怎麼寫:

package mytest;

public class TestSortUtil {
	public static int[] sort(int[] arr) {
		for(int i=0;i<arr.length;i++) {
			for(int j=i+1;j<arr.length;j++) { //i=0,j=1,2,3,4,...j初始值是j=i+1=0+1。後面j++,也就是第一個元素和後面的元素依次比較。
				if(arr[i]<arr[j]) { //當arr[i]後面的元素小於後面的元素交換。
					int tmp = arr[i];
					arr[i]=arr[j];
					arr[j]=tmp;
				}
                //print(arr);//如果想看排序過程開啟這裡的輸出就可以
			}
		}
		return arr;
	}
	public static void print(int[] arr) {
		for(int i=0;i<arr.length;i++) {
			System.out.print(" "+arr[i]);
		}
		System.out.println();
	}
	
	public static void main(String args[]) {
		int[] arr = {3,2,6,4,1,5,8,9,7};
		print(arr);
		print(sort(arr));
	}
}

氣泡排序就是這樣。

我們再來說說快速排序;先看百科定義:快速排序(Quicksort)是對氣泡排序的一種改進;它的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。

首先,要選一個分割點key(百科叫關鍵資料),通常是陣列的第一個資料。(分割點最好是隨機從數組裡取出來一個數據)

然後,就是第一遍排序,分割點值小的放前面,分割點大的資料放後面。一個從前向後比較arr[i]<key,取到第一個下標i;一個從後向前比較arr[j]>key,取到第一下標j;將第一個大於key的值和第一個小於key的值互換。i==j時比較到中間位置結束;這樣就分成了兩部分資料。舉例:int[] arr = {3,2,6,4,1,5,8,9,7}; 如果key是3,從前向後找到的第一個值是6,從後向前找到的第一個值是1;則6和1交換。

然後,前後兩部分分別再進行遞迴排序,這樣就可以將程式寫成一個遞迴呼叫。

下面再來看看程式

package mytest;

public class TestFastSort {

	
	public static int[] fastsort(int[] arr,int begin,int end) {
		int left = begin;//排序開始的時候:begin=0,end=N-1;
		int right = end;
		int key = arr[begin];//以第一個陣列元素作為關鍵資料,賦值給key,即key=arr[begin];
		
		while(left != right) {
			
			while(arr[left] < key) {//從前向後搜尋
				left++;
			}
			
			while(arr[right] > key) {//從後向前搜尋
				right--;
			}
			
			//此時arr[left]是第一個大於key的值;arr[right]是第一個小於key的值
			int temp = arr[left];
			arr[left] = arr[right];
			arr[right]=temp;
			//完成這兩個值交換
			
			print(arr);
		}//當left和right相同時,迴圈結束。
		
		if(begin<left) {
			fastsort(arr,begin,left-1);
		}
		if(right<end) {
			fastsort(arr,right+1,end);
		}
		
		return arr;
	}
	
	public static void print(int[] arr) {
		for(int i=0;i<arr.length;i++) {
			System.out.print(" "+arr[i]);
		}
		System.out.println();
	}
	
	public static void main(String args[]) {
		int[] arr = {3,2,6,4,1,5,8,9,0,7};
		print(arr);
		print(fastsort(arr,0,arr.length-1));
	}
}

如此,是不是明白了,為什麼說快速排序就是氣泡排序的優化了吧?其實就是先進行第一遍排序,選出中間值分成兩部分,然後對兩部分再分別排序。

那多的這一步,為什麼能比氣泡排序快呢?答降低了複雜度,那麼如何降低了複雜度?

先來看看冒泡順序:

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

氣泡排序耗時的操作有:比較 + 交換(每次交換兩次賦值)。時間複雜度如下:

1)        最好情況:序列是升序排列,在這種情況下,需要進行的比較操作為(n-1)次。交換操作為0次。即O(n)

2)        最壞情況:序列是降序排列,那麼此時需要進行的比較共有n(n-1)/2次。交換運算元和比較運算元一樣。即O(n^2)

3)        漸進時間複雜度(平均時間複雜度):O(n^2)

2.        空間複雜度:O(1)

從實現原理可知,氣泡排序是在原輸入陣列上進行比較交換的(稱“就地排序”),所需開闢的輔助空間跟輸入陣列規模無關,所以空間複雜度為:O(1)1.   

再來看看快速排序


1.        時間複雜度:O(nlog2n)

快速排序耗時的操作有:比較 + 交換(每次交換兩次賦值)。時間複雜度如下:

1)        最好情況:選擇的基準值剛好是中間值,分割槽後兩分割槽包含元素個數接近相等。因為,總共經過x次分割槽,根據2^x<=n得出x=log2n,每次分割槽需用n-1個元素與基準比較。所以O(nlog2n)

2)        最壞情況:每次分割槽後,只有一個分割槽包含除基準元素之外的元素。這樣就和氣泡排序一樣慢,需n(n-1)/2次比較。即O(n^2)

3)        漸進時間複雜度(平均時間複雜度):O(nlog2n)

2.        空間複雜度:O(1)

從實現原理可知,快速排序是在原輸入陣列上進行比較分割槽的(稱“就地排序”),所需開闢的輔助空間跟輸入陣列規模無關,所以空間複雜度為:O(1)