8. 排序(上):爲什麼插入排序比冒泡排序更受歡迎

一、幾種經典排序算法及其時間複雜度級別

二、如何分析一個排序算法?
1.學習排序算法的思路?明確原理、掌握實現以及分析性能。
2.如何分析排序算法性能?從執行效率、內存消耗以及穩定性3個方面分析排序算法的性能。
3.執行效率:從以下3個方面來衡量
1)最好情況、最壞情況、平均情況時間複雜度
2)時間複雜度的係數、常數、低階:排序的數據量比較小時考慮
3)比較次數和交換(或移動)次數
4.內存消耗:通過空間複雜度來衡量。針對排序算法的空間複雜度,引入原地排序的概念,原地排序算法就是指空間複雜度爲O(1)的排序算法。
5.穩定性:如果待排序的序列中存在值等的元素,經過排序之後,相等元素之間原有的先後順序不變,就說明這個排序算法時穩定的。
三、冒泡排序
1.排序原理


1)冒泡排序只會操作相鄰的兩個數據。
2)對相鄰兩個數據進行比較,看是否滿足大小關係要求,若不滿足讓它倆互換。
3)一次冒泡會讓至少一個元素移動到它應該在的位置,重複n次,就完成了n個數據的排序工作。
4)優化:若某次冒泡不存在數據交換,則說明已經達到完全有序,所以終止冒泡。
2.代碼實現

package com.wangzheng;


public class bubbleSort {
	
	public static void main(String args[]) {
		int[] array = {3,5,4,1,2,6};
		array = bubbleSort(array);
		for(int i=0;i<array.length;i++){
			System.out.print(array[i]);
		}
	}
	public static int[] bubbleSort(int[] array) {
		int n = 0;
		int temp = 0;
		n = array.length;
		
		while(n>0){
			boolean flag = false;
			for(int i=0;i<n-1;i++){
				if(array[i]>array[i+1]){
					temp = array[i];
					array[i] = array[i+1];
					array[i+1] = temp;
					flag = true;
				}								
			}
			n--;
			if(flag==false){
				break;
			}
		}
		return array;
		
	}
	
}

3.性能分析
1)執行效率:最小時間複雜度、最大時間複雜度、平均時間複雜度
最小時間複雜度:數據完全有序時,只需進行一次冒泡操作即可,時間複雜度是O(n)。
最大時間複雜度:數據倒序排序時,需要n次冒泡操作,時間複雜度是O(n^2)。
平均時間複雜度:通過有序度和逆序度來分析。
什麼是有序度?
有序度是數組中具有有序關係的元素對的個數,比如[2,4,3,1,5,6]這組數據的有序度就是11,分別是[2,4][2,3][2,5][2,6][4,5][4,6][3,5][3,6][1,5][1,6][5,6]。同理,對於一個倒序數組,比如[6,5,4,3,2,1],有序度是0;對於一個完全有序的數組,比如[1,2,3,4,5,6],有序度爲n*(n-1)/2,也就是15,完全有序的情況稱爲滿有序度。
什麼是逆序度?逆序度的定義正好和有序度相反。核心公式:逆序度=滿有序度-有序度。
排序過程,就是有序度增加,逆序度減少的過程,最後達到滿有序度,就說明排序完成了。
冒泡排序包含兩個操作原子,即比較和交換,每交換一次,有序度加1。不管算法如何改進,交換的次數總是確定的,即逆序度。
對於包含n個數據的數組進行冒泡排序,平均交換次數是多少呢?最壞的情況初始有序度爲0,所以要進行n*(n-1)/2交換。最好情況下,初始狀態有序度是n*(n-1)/2,就不需要進行交互。我們可以取箇中間值n*(n-1)/4,來表示初始有序度既不是很高也不是很低的平均情況。
換句話說,平均情況下,需要n*(n-1)/4次交換操作,比較操作可定比交換操作多,而複雜度的上限是O(n^2),所以平均情況時間複雜度就是O(n^2)。
以上的分析並不嚴格,但很實用,這就夠了。
2)空間複雜度:每次交換僅需1個臨時變量,故空間複雜度爲O(1),是原地排序算法。
3)算法穩定性:如果兩個值相等,就不會交換位置,故是穩定排序算法。
四、插入排序
1.算法原理


首先,我們將數組中的數據分爲2個區間,即已排序區間和未排序區間。初始已排序區間只有一個元素,就是數組的第一個元素。插入算法的核心思想就是取未排序區間中的元素,在已排序區間中找到合適的插入位置將其插入,並保證已排序區間中的元素一直有序。重複這個過程,直到未排序中元素爲空,算法結束
2.代碼實現

package com.wangzheng;

public class insertionSort {
	public static void main(String args[]) {
		int[] array = {3,5,4,1,2,6};
		array = insertSort(array);
		for(int i=0;i<array.length;i++){
			System.out.print(array[i]);
		}
	}
	public static int[] insertSort(int []array){
		int n = array.length;
		
		for(int i=1;i<n;i++){
			int value = array[i];
			int j = i-1;
			for(;j>=0;j--){
				if(array[j]>value){
					array[j+1] = array[j];
					if(j==0){
						array[j] = value;
					}
				}else{
					array[j+1] = value;	
					break;
				}							
			}
		}
		return array;
		
	}
}

3.性能分析
1)時間複雜度:最好、最壞、平均情況
如果要排序的數組已經是有序的,我們並不需要搬移任何數據。只需要遍歷一遍數組即可,所以時間複雜度是O(n)。如果數組是倒序的,每次插入都相當於在數組的第一個位置插入新的數據,所以需要移動大量的數據,因此時間複雜度是O(n^2)。而在一個數組中插入一個元素的平均時間複雜都是O(n),插入排序需要n次插入,所以平均時間複雜度是O(n^2)。
2)空間複雜度:從上面的代碼可以看出,插入排序算法的運行並不需要額外的存儲空間,所以空間複雜度是O(1),是原地排序算法。
3)算法穩定性:在插入排序中,對於值相同的元素,我們可以選擇將後面出現的元素,插入到前面出現的元素的後面,這樣就保持原有的順序不變,所以是穩定的。

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