算法(第四版)學習筆記(二)——初級排序算法
時間復雜度(Time Complexity):
總運算次數表達式中受n的變化影響最大的那一項(不含系數)(註:若算法中語句執行次數為一個常數,則時間復雜度為O(1))
- 一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)
空間復雜度(Space Complexity):
一個算法在運行過程中臨時占用存儲空間大小的量度(包括程序代碼所占用的空間,輸入數據所占用的空間和輔助變量所占用的空間這三個方面。)
註:
- 如當一個算法的空間復雜度為一個常量,即不隨被處理數據量n的大小而改變時,可表示為O(1);
- 當一個算法的空間復雜度與以2為底的n的對數成正比時,可表示為0(log2n);
- 當一個算法的空I司復雜度與n成線性比例關系時,可表示為0(n).
冒泡排序
選擇排序
步驟:(升序)
首先找到數組中最小的數,與數組第一位數交換位置(如果最小數是本身與本身交換)。接著在剩下的數中找第二小的數,與數組第二位數交換位置(如果第二小數是本身與本身交換)........按照相同步驟依次執行最後一個元素。
數據交換N次,數據比較(N-1)+(N-2)+........+3+2+1=N*(1+N-1)/2=N^2/2次(最後一個元素與自身交換)
時間復雜度:O(n2)
空間復雜度:O(1)
1 #include<stdio.h> 2 #include<malloc.h> 3 int main() 4 { 5 int n,i,j,min,temp; 6 scanf("%d",&n); 7 int *a=(int *)malloc(sizeof(int)*n); 8 for(i=0;i<n;i++) 9 scanf("%d",&a[i]); 10 for(i=0;i<n;i++) 11 { 12 min=a[i];//最小數 13 temp=i;//最小數在數組中的位置 14 for(j=i+1;j<n;j++) 15 { 16 if(min>a[j])//比較大小 17 { 18 min=a[j]; 19 temp=j; 20 } 21 } 22 a[temp]=a[i];//交換 23 a[i]=min; 24 } 25 for(i=0;i<n;i++) 26 printf("%d ",a[i]); 27 return 0; 28 }
- 運行時間與輸入無關,有序數組輸入其排序用時和相同長度的無序數組是一樣的。
- 數據移動最少,每次只需移動兩個數組
插入排序
直接插入排序
步驟:(升序)
將原數組分成兩組,一組為已排好序的數組A,另一組為亂序數組B。數組A倒序(A[length-1])每個元素依次與數組B的一個元素比較(從B[0]開始),若A組某元素比B組元素大,A組元素後退一位為,B組元素騰出空間,然後B組推下一個元素.
時間復雜度:O(n2)
空間復雜度:O(1)
1 #include<stdio.h> 2 #include<malloc.h> 3 void sort(int *a,int n); 4 int main() 5 { 6 int n,i; 7 scanf("%d",&n); 8 int *a=(int *)malloc(sizeof(int )*n); 9 for(i=0;i<n;i++) 10 scanf("%d",&a[i]); 11 sort(a,n); 12 for(i=1;i<n;i++) 13 printf("%d ",a[i]); 15 return 0; 16 } 17 int less(int a,int b) 18 { 19 if(a<b) return 1; 20 return 0; 21 } 22 void sort(int *a,int n) 23 { 24 int i,j,temp,k; 25 for(i=1;i<n;i++) 26 { 27 temp=a[i]; 28 for(j=i-1;j>=0&&less(temp,a[j]);j--) 29 { 30 a[j+1]=a[j]; 31 } 32 a[j+1]=temp; 33 } 34 }
- 插入排序所需時間取決於輸入元素的順序
- 插入排序更適用於部分有序的數組,和小規模數組
希爾排序
步驟:(升序)
為加快速度的插入排序,交換不相鄰的元素將數組部分變有序。使數組間隔h(h會改變)個元素有序。h在變化前,程序使h個元素間隔的小數組有序。
例:2—6—70(小數組每個元素間隔h個元素)..
時間復雜度:
空間復雜度:O(1)
#include<stdio.h> #include<malloc.h> //伸序 int less(int a[],int i,int j) { if(a[i]<a[j]) return 1; return 0; }
int main() { int n,h,i,j,temp,k; scanf("%d",&n); int *a=(int *)malloc(sizeof(int)*n); for(i=0;i<n;i++) scanf("%d",&a[i]); h=1; while(h<n/3) h=3*h+1; while(h>=1) { for(i=h;i<n;i++) { for(j=i;j>=h&&less(a,j,j-h);j-=h) { temp=a[j]; a[j]=a[j-h]; a[j-h]=temp; } } h/=3; } for(i=0;i<n;i++) printf("%d ",a[i]); return 0; }
疑問1:出現6—4—5這樣的小數組,排序後還是為無序小數組?
答:並不會出現6—4—5這樣的小數組,因為:
j=h 為 6—4小數組,會重新排序為有序4—6小數組
j=2h 為4—6—5小數組,會重新排序為有序4—5—6小數組
疑問2:如何選擇h的遞增數列?
書中用的的3*h+1與復雜遞增序列的性能相近,但比較簡單,所以書中將該遞增數列提出作為參考
並未找到最優遞增數列
優勢:
希爾排序比插入排序和選擇排序快得多,並且數組越大,優勢越大。
參考資料:《算法第四版》
如何計算時間/空間復雜度:http://www.cnblogs.com/zakers/archive/2015/09/14/4808821.html
算法(第四版)學習筆記(二)——初級排序算法