數據結構之進階排序(希爾排序、快速排序、歸併排序)

我們學習了最基礎的三種排序,它們都有個共同點,就是時間複雜度都是O(n^2),

在long long ago,科學家們以爲排序時間複雜度已經到了極限了,不可能存在低於O(n^2)

的排序,但是呢!有個傢伙叫希爾的。。。。。(此處略去1W字),然後希爾排序就出現了,

希爾排序的本質還是插入排序(什麼?插入排序,好熟悉啊!),前面我們學了插入排序,

那麼這個希爾到底做了什麼使它的時間複雜度降低到O(n^2)呢?閒話少扯,上代碼。

#include <stdio.h>
#include <stdlib.h>

void print(int array[], int len)
{
    int i = 0;
    for (i = 0; i < len; i++)
    {
        printf("%d ",array[i]);    
    }     
    
    printf("\n");
}

void swap(int array[], int i, int j)
{
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}

void ShellSort(int array[], int len)
{
    int i = 0;
    int j = 0;
    int k = -1;
    int temp = -1;
    int gap = 0;
    
    do
    {
        gap = gap / 3 + 1;
        
        for (i = gap; i < len; i += gap)
        {
            k = i;
            temp = array[k];
            
            for (j = i - gap; (j >= 0) && (array[j] >= temp); j--)
            {
                array[j + gap] = array[j];
                k = j;
            }    
            
            array[k] = temp;
        }
    } while(gap > 1);     
}

int main(int argc, char *argv[])
{
    int a[] = {22,44,11,66,77,44,33};
    int len = sizeof(a) / sizeof(int);
    
    print(a, len);
    
    ShellSort(a, len);
  
    print(a, len);
  
    system("PAUSE");	
    return 0;
}
是不是挺簡單的,希爾排序的主要技巧是在gap的設計,但gap具體除以多少暫時還沒有規定,

你把gap設爲1,那就是最壞的情況,也就是成了插入排序。


下面我們來說下項目中常用到的快速排序,在希爾突破了O(n^2)之後,很多科學家也加入研究中,

所以也就有了快速排序。快速排序它很巧妙的把遞歸應用到裏面,在第一次查找的時候,找到一個元素,

這個元素左邊都是小於它,右邊都是大於它,所以第一個元素的位置就確定了,然後左邊和右邊依次遞歸,

整個算法實現非常巧妙,不得不佩服啊!上代碼。

#include <stdio.h>
#include <stdlib.h>

void print(int array[], int len)
{
    int i = 0;
    for (i = 0; i < len; i++)
    {
        printf("%d ",array[i]);    
    }     
    
    printf("\n");
}

void swap(int array[], int i, int j)
{
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}

int Postition(int array[], int low, int high)
{
    int pv = array[low];
    
    while (low < high)
    {
        while ((low < high) && (array[high] >= pv))
        {
            high--;      
        }      
        
        swap(array, low, high);
        
        while ((low < high) && (array[low] <= pv))
        {
            low++;      
        }
        
        swap(array, low, high);
    }
    
    array[low] = pv;
    
    return low;
}

void QSort(int array[], int low, int high)
{
    if (low < high)
    {
        int pos = Postition(array, low, high);
        
        QSort(array, low, pos - 1);
        QSort(array, pos + 1, high);        
    }
}

void QuickSort(int array[], int len)
{
    QSort(array, 0, len - 1);   
}

int main(int argc, char *argv[])
{
    int a[] = {22,44,11,66,77,44,33};
    int len = sizeof(a) / sizeof(int);
    
    print(a, len);
    
    QuickSort(a, len);
  
    print(a, len);
  
    system("PAUSE");	
    return 0;
}

看明白了嗎?是不是言簡意賅,好了下面我們介紹下歸併排序,爲什麼會存在歸併排序呢?

主要是因爲希爾排序和快速排序不是穩定的排序,在操作過程中有大量的數據移動,所以,

就產生了一種叫歸併排序的東東,那麼什麼是歸併排序呢?簡單的說就是,把一組數據,

分成幾個已經排好的數組,然後把他們合併成一個數組(百度吧!這個一下數不清楚)

好了,show time!

#include <stdio.h>
#include <stdlib.h>

void print(int array[], int len)
{
    int i = 0;
    for (i = 0; i < len; i++)
    {
        printf("%d ",array[i]);    
    }     
    
    printf("\n");
}

void Merge(int src[], int dest[], int low, int mid, int high)
{
    int i = low;
    int j = mid + 1;
    int k = low;
    
    while ((i <= mid) && (j <= high))
    {
        if (src[i] < src[j])
        {
            dest[k++] = src[i++];           
        }      
        else
        {
            dest[k++] = src[j++];    
        }
    }     
    
    while (i <= mid)
    {
        dest[k++] = src[i++];      
    }
    
    while (j <= high)
    {
        dest[k++] = src[j++];      
    }
}

void MSort(int src[], int dest[], int low, int high, int max)
{
    if (low == high)
    {
        dest[low] = src[low];    
    }
    else
    {
        int mid = (low + high) / 2;
        int* space = (int*)malloc(sizeof(int) * max);
        
        if (space != NULL)
        {
            MSort(src, space, low, mid, max);
            MSort(src, space, mid + 1, high, max);
            Merge(space, dest, low, mid, high);          
        }
        
        free(space);
    } 
}

void MergeSort(int array[], int len)
{
    MSort(array, array, 0, len - 1, len);     
}

int main(int argc, char *argv[])
{
    int a[] = {22,44,11,66,77,44,33};
    int len = sizeof(a) / sizeof(int);
    
    print(a, len);
    
    MergeSort(a, len);
  
    print(a, len);
  
    system("PAUSE");	
    return 0;
}

是不是跟快速排序有點像呢?但是它保證穩定性的前提下,犧牲了空間,就是每次分組之後申請的堆空間。

上述三種排序的時間複雜度都是O(nlogn),所以在科學界不斷的努力下,排序算法的時間複雜度還是可以改變的嘛!!!


    

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