C語言實現快速排序


我覺得冒泡排序是比較簡單的;

所以今天我們實現一個叫做快速排序的;

 

Problem

你想要將(4,3,5,1,2)排序成(1,2,3,4,5)

你決定使用最簡單的快速排序;

Solution

首先,打開你的terminal,我寫得C代碼通常都是用vi編輯,gcc編譯;

vim quickSortSample.c

因為,快速排序需要對數據進行分割然后處理,再分割再處理;

顯然需要一個遞歸的過程;

所以,我們先把遞歸結束條件寫好;

#include <stdio.h>

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;                                                                   
}

也就是說,當輸入只有一個數字就沒有必要排序啦!直接返回;

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;                                                                   

    p = a[n / 2];   // Get the middle element as pivot ..                                 

    for ( i = 0, j = n -1;; i++, j--) {                                                   

    //TODO ...

    }       
}

注意: p = a[n / 2];的目地是獲取數組中得中間位置的數據;

我們都知道,數組下標是整數,因此,如果n=3那么n/2應該是1,此時正好平分數組;

若是,n=4那么n/2應該是2,而此時它們就不完全是平分數組啦;

for循環的作用是為了從前后兩個方向分別遍歷;

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;                                                                   

    p = a[n / 2];   // Get the middle element as pivot ..                                 

    for ( i = 0, j = n -1;; i++, j--) {                                                   
        while (a[i] < p)                                                                  
            i++;
        while (p < a[j])                                                                  
            j--;
    }           
}

注意:我們在for循環中又進行啦while循環;

它的作用是對元素進行遍歷,假設左邊的數據沒有p中保存的元素大,那么繼續尋找,並且把i自增;

當找到比p大的或者相等得則停止第一個while循環;

例如:如果數組(2,5,3,1,4)那么p顯然是3,當while循環發現5大於3時停止循環,此時i=1;

同理,第二個while循環中,p依然是3,當while循環第一次發現4大於3則繼續循環此時j=4;

當while循環到j=3時,得到的元素是1,1不大於3所以停止循環,此時得到的j=3;

好啦!那么我們知道在for循環中沒有明確指定循環停止條件;

它該什么時候停止呢?

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;                                                                   

    p = a[n / 2];   // Get the middle element as pivot ..                                 

    for ( i = 0, j = n -1;; i++, j--) {                                                   
        while (a[i] < p)                                                                  
            i++;
        while (p < a[j])                                                                  
            j--;
        if ( i >= j)
            break;
    }   
}

注意:當i>=j意味着此時數據已經全部遍歷完了;

因為i與j分布在數組左右兩部分,當它們重合,當然也就表明它們遍歷完啦;

剛才,我們的兩個while循環分別找到啦一個左邊比p大得元素,和一個右邊比p小的數字;

顯然這兩個元素應該交換位置的;

那么怎么實現呢;

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;                                                                   

    p = a[n / 2];   // Get the middle element as pivot ..                                 

    for ( i = 0, j = n -1;; i++, j--) {                                                   
        while (a[i] < p)                                                                  
            i++;
        while (p < a[j])                                                                  
            j--;
        if ( i >= j)
            break;
        tmp = a[i]; a[i] = a[j]; a[j] = tmp;    //swap both ..                            
    }   
}

我們看到了,在冒泡排序中也用到得交換語句;

此時我們完全遍歷了一遍數組;

我們在main函數中測試一下;

#include <stdio.h>

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;

    p = a[n / 2];   // Get the middle element as pivot ..

    for ( i = 0, j = n -1;; i++, j--) {
        while (a[i] < p)
            i++;
        while (p < a[j])
            j--;
        if ( i >= j)
            break;
        tmp = a[i]; a[i] = a[j]; a[j] = tmp;    //swap both ..
    }   
}


int main(void)
{
    int a[] = { 2, 5, 3, 1, 4}; 
    int n = sizeof a /sizeof a[0];
    int i;
    for (i = 0; i < n; i++)
        printf("%d%s", a[i], i == n -1 ? "\n" : " ");
    quick_sort(a, n); 
    for (i = 0; i < n; i++)
        printf("%d%s", a[i], i == n -1 ? "\n" : " ");
    
    return 0;
}

main函數的語句都非常容易懂,就不解釋啦;

看看編譯運行的結果:

顯然,運行的結果是我們預期的;

3左邊的都比3小啦!那若果數據多一些呢;

比如{ 2, 5, 7, 3, -1, 1, 4}我們會發現左邊有兩個元素都比3大,理論上要進行兩次交換;

顯然當它交換完[1]與[5]元素后,它又是怎么繼續的我們關心這個問題;

顯然交換完數據后,又進入for循環;

for循環沒有結束條件,因此,i++,j--完成后,此時i=2,j=4;

 

接下來執行兩個while發現,第一個while發現a[2]是7 不小於p此時不執行i++;

同樣在第二個while中也發現a[4]是-1不大於p此時不執行j--;

然后到if語句不成立,因此繼續進行數據交換;

測試如下數據;

#include <stdio.h>

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;

    p = a[n / 2];   // Get the middle element as pivot ..

    for ( i = 0, j = n -1;; i++, j--) {
        while (a[i] < p)
            i++;
        while (p < a[j])
            j--;
        if ( i >= j)
            break;
        tmp = a[i]; a[i] = a[j]; a[j] = tmp;    //swap both ..
    }
}


int main(void)
{
    int a[] = { 2, 5, 7, 3, -1, 1, 4};
    int n = sizeof a /sizeof a[0];
    int i;
    for (i = 0; i < n; i++)
        printf("%d%s", a[i], i == n -1 ? "\n" : " ");
    quick_sort(a, n);
    for (i = 0; i < n; i++)
        printf("%d%s", a[i], i == n -1 ? "\n" : " ");

    return 0;
}

我們會得到如下結果:

顯然,我們已經得到啦p左邊都是小於p的;

右邊則是大於p的;

符合我們的設想;

為了把整個數組正確排序,我們需要分別又對兩部分重復一遍剛才的操作;

好,我們遞歸的調用函數,並且把數組的兩部分元素傳遞到函數中;

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;

    p = a[n / 2];   // Get the middle element as pivot ..

    for ( i = 0, j = n -1;; i++, j--) {
        while (a[i] < p)
            i++;
        while (p < a[j])
            j--;
        if ( i >= j)
            break;
        tmp = a[i]; a[i] = a[j]; a[j] = tmp;    //swap both ..
    }   

    quick_sort( a, i); 
    quick_sort( a + i, n - i); 
}

注意:

 

第一個遞歸調用處理數組的前部分,a對應的是數組的首地址,i是指對應的元素個數;

第二個遞歸調用處理數組后部分,a + i指的當然是首地址加偏移地址,如果你對偏移地址有問題的話,應該看看計算機尋址方式的資料啦;

接下來看運行結果:

 

最后,我們把所有代碼附上:

#include <stdio.h>

void quick_sort( int *a, int n)
{
    int i, j, p, tmp;
    if (n < 2)  return;

    p = a[n / 2];   // Get the middle element as pivot ..

    for ( i = 0, j = n -1;; i++, j--) {
        while (a[i] < p)
            i++;
        while (p < a[j])
            j--;
        if ( i >= j)
            break;
        tmp = a[i]; a[i] = a[j]; a[j] = tmp;    //swap both ..
    }   

    quick_sort( a, i); 
    quick_sort( a + i, n - i); 
}


int main(void)
{
    int a[] = { 2, 5, 7, 3, -1, 1, 4}; 
    int n = sizeof a /sizeof a[0];
    int i;
    for (i = 0; i < n; i++)
        printf("%d%s", a[i], i == n -1 ? "\n" : " ");
    quick_sort(a, n); 
    for (i = 0; i < n; i++)
        printf("%d%s", a[i], i == n -1 ? "\n" : " ");
    
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM