1. 程式人生 > >內部排序(二)快速排序

內部排序(二)快速排序

快速排序(QuickSort)是對氣泡排序的一種改進,故在介紹快速排序之前,我們先介紹氣泡排序。

1、氣泡排序

原理:將第一個記錄的關鍵字和第二個記錄的關鍵字進行比較,若為逆序,則交換(假設正序輸出),然後比較第二個記錄和第三個記錄的關鍵字。以此類推,直至第n-1個記錄和第n個記錄的關鍵字進行比較,這是第一趟。然後第二趟,第三趟……
過程演示

演算法程式碼:(演算法很簡單,雙重迴圈)

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

void main(){
    int array[5] = { 5, 3, 1, 2
, 8 }; int temp=array[0];//臨時變數 int length=5; for (int i = 0; i < length-1; i++){//外迴圈控制趟數 for (int j = 0; j < length-1-i; j++){//內迴圈控制比較 if (array[j]>array[j+1]){ temp = array[j]; array[j] = array[j+1]; array[j + 1] = temp; } } } for
(int k = 0; k < length; k++){ printf("%d", array[k]); } system("pause"); }

2、快速排序

原理:快排是對氣泡排序的一種改進。基本思想是通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,已達到整個序列有序。
演算法敘述:一趟排序的具體做法是:附設兩個指標low和high,它們的初值分別是low和high,設樞軸記錄的關鍵字為pivotkey,則首先從high所指位置向前搜尋找到第一個關鍵字小於pivotkey的記錄,和樞軸記錄交換之(即逆序交換,假設我們要從小到大輸出),然後從low所指位置起向後搜尋,找到第一個關鍵字大於pivotkey的記錄,和樞軸相互交換(逆序交換)重複這兩部,直至low=high為止。
此時記錄被樞軸分成兩部分,左邊的都比樞軸小,右邊的都比樞軸大。
然後進行第二趟,將樞軸左邊的全部記錄再當成一個記錄序列,再次使用剛剛的方法。
演算法演示


(i就是low,j就是high)
這裡寫圖片描述
演算法程式碼


#define MAXSIZE 20
typedef int KeyType;//定義關鍵字型別為int
typedef char InfoType;//定義其他資訊型別為char

typedef struct{//定義記錄型別
    KeyType key;
    InfoType otherinfo;
}RedType;
typedef struct{//定義順序表型別
    RedType r[MAXSIZE + 1];//r[0]閒置或作為哨兵
    int length;//順序表的長度
}SqList;

//在實現我們剛剛的演算法時,每交換一次,需進行三次移動。
//但實際上對樞軸記錄的移動是多餘的,
//因為只有在一趟排序結束時,即low=high的位置才是樞軸記錄的最後位置。
//故我們將樞軸暫存到r[0],一趟結束後再移到正確位置。

//此函式進行一趟排序。返回樞軸的位置。(此過程的演示只需把上圖每一次交換的樞軸量用空白代替就行)
int partition(SqList *L, int low, int high){
    int pivotkey;
    L->r[0] = L->r[low];//用子表的第一個記錄作為樞軸記錄。
    pivotkey = L->r[low].key;//用pivotpoint標識

    while (low < high){

        while (low<high&&L->r[high].key>=pivotkey){//從後向前找到要(向前)移動的關鍵字的下標
            high--;
        }
        L->r[low] = L->r[high];//把找的的點(向前)移動

        while (low < high&&L->r[low].key <= pivotkey){//從前往後找到要(向後)移動的關鍵字的下標
            low++;
        }
        L->r[high] = L->r[low];//把找到的點(向後)移動

    }
    L->r[low] = L->r[0];//樞軸量放到該放置的位置

    return  low;//返回樞軸量的下標
}

void QSort(SqList *L, int low, int high){
    //對順序表中子序列L->r[low...high]作快速排序
    int pivotloc;

    if (low<high){//如果長度大於1
        pivotloc = partition(L, low, high);//進行一趟排序,將L->r[low...high]分為兩個子序列,本趟樞軸下標賦給pivotloc
        QSort(L, low, pivotloc - 1);//對低子表進行遞迴排序
        QSort(L, pivotloc + 1, high);//對高子表進行遞迴排序
    }

}

void QuickSort(SqList *L){
    QSort(L,1,L.length);
}

評價
點:快速排序的平均時間為T(n)=knInn,其中n為待排序列中記錄的個數,k為某個時間常數,經驗證明,在所有同數量級的此類排序方法中,快速排序的常數因子k最小。因此,就平均時間而言,快速排序是目前被認為最好的一種內部排序方法。
點:若初始記錄序列按關鍵字有序或基本有序時,快速排序將退化為氣泡排序,時間複雜度為O(n^2).改進的方法是依“三者取中”的法則來選樞軸記錄。(此處不詳細介紹)