1. 程式人生 > >算法(第四版)學習筆記(二)——初級排序算法

算法(第四版)學習筆記(二)——初級排序算法

space 倒序 優勢 name 算法 turn 資料 eply n)


時間復雜度(Time Complexity):

總運算次數表達式中受n的變化影響最大的那一項(不含系數)(註:若算法中語句執行次數為一個常數,則時間復雜度為O(1))
若T(n)/f(n)求極限可得到一常數c,則時間復雜度T(n)=O(f(n))。
  • 一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)
  • 算法的基本操作重復執行的次數是模塊n的某一個函數f(n)
隨著模塊n的增大,算法執行的時間的增長率和f(n)的增長率成正比,所以f(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

 

算法(第四版)學習筆記(二)——初級排序算法