排序算法-綜述

一、冒泡排序算法:算法

冒泡排序算法是最簡單也是最基本的排序算法之一,算法的原理爲以下:數組

原理:將數據當中的每個元素與以後的元素進行對比,若是當前元素比序列後的元素的值小,則交換二者的順序,依次類推,直到最後一個數據完成排序便可!數據結構

時間複雜度:O(n2)ide

 API實現以下(兩層for循環嵌套實現):函數

 1 int BubbleSort(int *In, int N)
 2 {
 3     int temp;
 4     for (int i = 0; i < N; i++) {
 5         for (int j = i + 1; j < N; j++) {
 6             if (In[i] > In[j]) {
 7                 temp = In[i];
 8                 In[i] = In[j];
 9                 In[j] = temp;
10             }
11         }
12     }
13     return 1;
14 }

二、插入排序算法:ui

插入排序算法是最基本的排序算法之一,少許數據的排序,其效率較高,算法的原理爲以下:spa

原理:從第一個數值開始排序,在每個P循環以後,0-P之間的全部元素都是已經完成排序了,P以後的第一個數據做爲插值,和前面的順序序列對比並插入正確的位置!code

時間複雜度:O(n2),對於基本排列好序列的數據,插入排序算法的時間複雜度爲O(n)。blog

 API實現以下:排序

 1 int InsertSort(int *In, int N)
 2 {
 3     int P, i, temp;
 4     for (P = 1; P < N; P++) {
 5         temp = In[P];
 6         for (i = P; i > 0 && temp < In[i - 1]; i--) {
 7             In[i] = In[i - 1];
 8         }
 9         In[i] = temp;
10     }
11     return 1;
12 }

三、希爾排序算法:

希爾排序算法的平均時間複雜度較低,算法的原理以下:

原理:算法在運行的過程當中,每次將前面的數據與其間隔stride步長位置的數據進行對比,完成當前stride的所有對比以後,將stride縮小爲原來的一半,以此類推,最後stride爲1,這個時候對比的就是相鄰的元素,對比完成,序列同時完成了排序。

時間複雜度:O(n*log(n))

API_0實現以下(常規的希爾序列初始增量:N/2. N爲數據的長度):

 1 int ShellSort(int *In, int N)
 2 {
 3     int i, j, stride,Temp;
 4     /* 這裏須要注意的是,stride最終的結果爲0:當stride=1時,stride/=2獲得的stride=floor(0.5)=0,因此循環退出 */
 5     for (stride = N / 2; stride > 0; stride /= 2) {
 6         for (i = stride; i < N; i++) {
 7             Temp = In[i];
 8             for (j = i; j >= stride && Temp < In[j - stride] ; j -= stride) {
 9                     In[j] = In[j - stride];
10             }
11             In[j] = Temp;
12         }
13     }
14     return 1;
15 }

API_1實現以下(希爾Hibbard增量序列:Hibbard:{1, 3, ..., 2^k-1})

注:這是一種衝破二次時間屏障的算法

 1 int ShellSort_Hibbard(int *In, int N) // 時間複雜度最壞的狀況爲o(N^3/2)
 2 {
 3     int i, j, stride, Temp;
 4     int k = log2(N / 2 + 1);
 5     // printf("The k is:%d\n", k);
 6     /* 這裏須要注意的是,stride最終的結果爲0:當stride=1時,stride/=2獲得的stride=floor(0.5)=0,因此循環退出 */
 7     for (stride = (2<<k) - 1; stride > 0 && k >= 1; stride = (1<<k) - 1) { // 注意這裏的左移運算的優先級低於減法的優先級,因此要打上括號
 8         // printf("The stride is:%d\n", stride);
 9         for (i = stride; i < N; i++) {
10             Temp = In[i];
11             for (j = i; j >= stride && Temp < In[j - stride]; j -= stride) {
12                 In[j] = In[j - stride];
13             }
14             In[j] = Temp;
15         }
16         k -= 1;
17     }
18     return 1;
19 }

四、選擇快速排序算法:

快速排序算法的平均時間複雜度低,比較適合大量數據的排序算法,算法的原理以下:

原理:快速排序算法的狀況和歸併排序算法比較類似!詳細原理參考這裏:https://www.jianshu.com/p/7631d95fdb0b

時間複雜度:O(n*log(n))

API實現以下:

#define Cutoff 3
void Swap(int *A, int *B)
{
    int Temp;
    Temp = *A;
    *A = *B;
    *B = Temp;
}
int Median3(int A[], int left, int right) // 尋找樞紐值
{
    int center = (left + right) / 2;
    int Temp;

    if (A[left] > A[center])
        Swap(&A[left], &A[center]);
    if (A[left] > A[right])
        Swap(&A[left], &A[right]);
    if (A[center] > A[right])
        Swap(&A[center], &A[right]);

    Swap(&A[center], &A[right - 1]); // 將樞紐值保存在數組的邊緣
    return A[right - 1];  // return pivot-返回樞紐值
}
void QSort(int A[], int left, int right)
{
    int i, j;
    int pivo;
    if (left + Cutoff <= right) { // 小數組的處理交給插值排序的方法,速度比較快一些
        pivo = Median3(A, left, right); // 樞紐值求解
        i = left; j = right - 1;
        for (;;)
        {
            while (A[++i] < pivo) { } // 分割策略
            while (A[--j] > pivo) { } // 分割策略
            if (i < j)
                Swap(&A[i], &A[j]);
            else
                break;
        }
        Swap(&A[i], &A[right - 1]); // Swap函數屬於外部調用,爲了提升算法的效率能夠直接顯式寫出代碼,不用callSwap函數

        QSort(A, left, i-1); // 分割以後的遞歸調用
        QSort(A, i+1, right); // 分割以後的遞歸調用
    }
    else {
        InsertSort(A + left, right - left + 1); // 插值排序算法
    }

}
void QuickSort(int A[], int N)
{
    QSort(A, 0, N-1);
}

五、堆排序算法:

堆排序算法的平均時間複雜度較低,算法的原理以下:

原理:堆排序算法主要使用了堆數據結構的特色,建立二叉堆,並進行堆排序,便可完成數據的排序。

時間複雜度:O(n*log(n))

API實現以下:

 1 #define LeftChild(i) (2*(i)+1)
 2 void PerDown(int A[], int i, int N) // 降過濾法完成二叉堆的生成
 3 {
 4     int Child;
 5     int Tmp;
 6     for (Tmp = A[i]; LeftChild(i) < N; i = Child) {
 7         Child = LeftChild(i);
 8         if (Child != N - 1 && A[Child + 1] > A[Child])
 9             Child++;
10         if (Tmp < A[Child])
11             A[i] = A[Child];
12         else
13             break;
14     }
15     A[i] = Tmp;
16 }
17 void Swap(int *A, int *B)
18 {
19     int Temp;
20     Temp = *A;
21     *A = *B;
22     *B = Temp;
23 }
24 void HeapSort(int A[], int N)
25 {
26     int i;
27     for (i = N / 2; i >= 0; i--) {
28         PerDown(A, i, N); // 建立二叉堆
29     }
30     for (i = N - 1; i > 0; i--)
31     {
32         Swap(&A[0], &A[i]); // Delet the Max Element
33         PerDown(A, 0, i);
34     }
35 }

六、桶排序算法:

堆排序算法的平均時間複雜度較低,算法的原理以下:

原理:桶排序算法主要使用了相似於散列表的特色,將待排序的數據的數據內容統計起來,按照index桶的位置來確保數據的順序問題,從而完成了桶排序的任務!

時間複雜度:O(n)

API實現以下:

 1 void BucketSort(int A[], int N, int MAX) // 對於排序小整數的狀況,buckect桶排序算法很是的適合
 2 {
 3     int *Bucket = (int *)malloc(sizeof(int)*MAX);
 4     int index;
 5     for (int i = 0; i < MAX; i++) {
 6         *(Bucket + i) = 0;
 7     }
 8     for (int i = 0; i < N; i++) {
 9         index = A[i];
10         Bucket[index] += 1;
11     }
12     index = 0;
13     for (int i = 0; i < MAX; i++) {
14         while (Bucket[i] != 0) {
15             A[index] = i;
16             index += 1;
17             Bucket[i] -= 1;
18         }
19     }
20 }

未完待續~

相關文章
相關標籤/搜索