[算法] 關於快速排序的四種寫法

前序

說到排序算法,應該算是家喻戶曉,人人皆知的大路貨了。可是每每這些爲人所熟知的東西中,也存在一些能夠使人琢磨的細節。算法

這不,某天深夜,無所事事,大概是太寂寞,在思念了一番妹子之後,腦子裏忽然閃過了快速排序,遂在腦子中模擬了一遍快速排序的運行過程,之前只是死記硬背代碼,沒有去探究其運做的流程,因而在一些細節處陷入了沉思和迷惑,致使腦回路短路,當場打開鬥魚看了會球。網絡

首先你們都知道,快排主要有兩部分,分段(Partition)和遞歸(Recursive)。分段既將一組數據相對一個參考值分爲兩段,左段比參考值小,右端比參考值大,而後再遞歸對這兩段進行分段。那麼快排的關鍵部分天然就是這個分段算法,有了分段算法,加上遞歸,一個快排算法就寫好了。函數

固然別小看了這個分段算法,是須要好好琢磨一番的。主要是一些臨界值和極端狀況的考慮,個人迷惑即是於此。因而查找了一些書籍和網絡資源,加上本身的思路,總結了四種不一樣的分段算法。細節控能夠來好好感覺一下。spa

一. 填坑法

之因此叫填坑法,是其運做過程就像填坑同樣。並且一點都不坑,代碼形式很是好理解。指針

圖片描述

代碼以下:code

int partition(int a[], int start, int end){
    int p = a[start];
    while(start < end){
        while(a[end] >= p && start < end) end--;
        a[start] = a[end];
        while(a[start] < p && start < end) start++;
        a[end] = a[start];
    }
    a[start] = p;
    return start;
}

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int mid = partition(a, start, end);
    qs(a, start, mid-1);
    qs(a, mid+1, end);
}

二. 交換法

交換法,顧名思義就是要對兩邊的元素進行交換,再代碼形式中用到swap函數。其流程以下:blog

圖片描述

代碼以下:排序

void swap(int* a, int* b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int a[], int start, int end){
    int pivot = a[start];
    int p = start+1;
    int q = end;
    while(p <= q){
        while(a[p] < pivot && p <= q) p++;
        while(a[q] >= pivot && p <= q) q--;
        if(p < q){
            swap(&a[p], &a[q]);
        }
    }
    swap(&a[start], &a[q]);
    return q;
}

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int mid = partition(a, start, end);
    qs(a, start, mid-1);
    qs(a, mid+1, end);
}

能夠看出這個方法和第二個方法有什麼不一樣的地方,爲何要選第二個元素爲start遞歸

三. 順序遍歷法

上面兩種方法是維護了一個start,一個end指針,逐步向中間趨近的過程。而順序遍歷用一次遍歷完成對數據的分段。圖片

圖片描述

代碼以下:

void swap(int* a, int* b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int a[], int start, int end){
    int pivot = a[end];
    int storeIndex = start;
    for(int i = start; i < end; i++){
        if(a[i] < pivot){
            swap(&a[storeIndex], &a[i]);
            storeIndex++;
        }
    }
    swap(&a[storeIndex], &a[end]);
    return storeIndex;
}

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int mid = partition(a, start, end);
    qs(a, start, mid-1);
    qs(a, mid+1, end);
}

四. 另類交換法

這個方法和以前的交換法的思路相同,可是它不返回mid值,因此索性稱之爲另類交換法吧。運做的流程就不作解釋,直接上代碼,各位客官姑且一看。

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int pivot = a[start];
    int p = start;
    int q = end;
    while(1){
        while(a[p] < pivot) p++;
        while(a[q] > pivot) q--;
        if(p >= q){
            break;
        }
        swap(&a[p], &a[q]);
        p++;
        q--;
    }
    qs(a, start, p-1);
    qs(a, q+1, end);
}

後記

這四種算法用了四種不一樣的解決問題的思路,雖然都是細節上的不一樣,可是細細去想一下也能領會其中到奧妙。第一次在sf上發文章,也是爲了鞏固和牢記本身這麼多天琢磨的東西。若是有什麼錯誤和不足,也請各位看客多多指正和補充。

相關文章
相關標籤/搜索