31、數據結構與算法 - 排序 (三)快速排序

快速排序


設計一個函數(QSort)
QSort 函數思路:
判斷low 是否小於high;
求得樞軸,並且將數組樞軸左邊的關鍵字都比它小,右邊的關鍵字都比樞軸對應的關鍵字大;
將數組一份爲二,對低子表進行排序,對高子表進行排序

設計一個函數(Partition)
Partition 函數的功能
選取當中一個關鍵字作爲樞軸;
將它放在一個合適的位置上,使得它的左邊的值都比它小,右邊的值都比它大

 

 

 

 

 

 

優化

 

 

代碼實現

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;

//1.排序算法數據結構設計
//用於要排序數組個數最大值,可根據需要修改
#define MAXSIZE 10000
typedef struct
{
    //用於存儲要排序數組,r[0]用作哨兵或臨時變量
    int r[MAXSIZE+1];
    //用於記錄順序表的長度
    int length;
}SqList;

//2.排序常用交換函數實現
//交換L中數組r的下標爲i和j的值
void swap(SqList *L,int i,int j)
{
    int temp=L->r[i];
    L->r[i]=L->r[j];
    L->r[j]=temp;
}

//3.數組打印
void print(SqList L)
{
    int i;
    for(i=1;i<L.length;i++)
        printf("%d,",L.r[i]);
    printf("%d",L.r[i]);
    printf("\n");
}
//13.快速排序-對順序表L進行快速排序
//③交換順序表L中子表的記錄,使樞軸記錄到位,並返回其所在位置
//此時在它之前(後)的記錄均不大(小)於它
int Partition(SqList *L,int low,int high){
    int pivotkey;
    //pivokey 保存子表中第1個記錄作爲樞軸記錄;
    pivotkey = L->r[low];
    //① 從表的兩端交替地向中間掃描;
    while (low < high) {
        
        //② 比較,從高位開始,找到比pivokey更小的值的下標位置;
        while (low < high &&  L->r[high] >= pivotkey)
            high--;
        //③ 將比樞軸值小的記錄交換到低端;
        swap(L, low, high);
        //④ 比較,從低位開始,找到比pivokey更大的值的下標位置;
        while (low < high && L->r[low] <= pivotkey)
            low++;
        //⑤ 將比樞軸值大的記錄交換到高端;
        swap(L, low, high);
        
    }
    
    //返回樞軸pivokey 所在位置;
    return low;
}

//② 對順序表L的子序列L->r[low,high]做快速排序;
void QSort(SqList *L,int low,int high){
    int pivot;
    
    if(low < high){
        //將L->r[low,high]一分爲二,算出中樞軸值 pivot;
        pivot = Partition(L, low, high);
        printf("pivot = %d L->r[%d] = %d\n",pivot,pivot,L->r[pivot]);
        //對低子表遞歸排序;
        QSort(L, low, pivot-1);
        //對高子表遞歸排序
        QSort(L, pivot+1, high);
    }
    
}

//① 調用快速排序(爲了保證一致的調用風格)
void QucikSort(SqList *L){
    QSort(L, 1, L->length);
}
//14 快速排序-優化
int Partition2(SqList *L,int low,int high){
   
    int pivotkey;
    
    /**1.優化選擇樞軸**/
    //① 計算數組中間的元素的下標值;
    int m = low + (high - low)/2;
    //② 將數組中的L->r[low] 是整個序列中左中右3個關鍵字的中間值;
    //交換左端與右端的數據,保證左端較小;[9,1,5,8,3,7,4,6,2]
    if(L->r[low]>L->r[high])
        swap(L, low, high);
    //交換中間與右端的數據,保證中間較小; [2,1,5,8,3,7,4,6,9];
    if(L->r[m]>L->r[high])
        swap(L, high, m);
    //交換中間與左端,保證左端較小;[2,1,5,8,3,7,4,6,9]
    if(L->r[m]>L->r[low])
        swap(L, m, low);
    //交換後的序列:3,1,5,8,2,7,4,6,9
    //此時low = 3; 那麼此時一定比選擇 9,2更合適;
    
    
    /**2.優化不必要的交換**/
    //pivokey 保存子表中第1個記錄作爲樞軸記錄;
    pivotkey = L->r[low];
    //將樞軸關鍵字備份到L->r[0];
    L->r[0] = pivotkey;
    
    //① 從表的兩端交替地向中間掃描;
    while (low < high) {
        //② 比較,從高位開始,找到比pivokey更小的值的下標位置;
        while (low < high &&  L->r[high] >= pivotkey)
            high--;
        
        //③ 將比樞軸值小的記錄交換到低端;
        //swap(L, low, high);
        //③ 採用替換的方式將比樞軸值小的記錄替換到低端
        L->r[low] = L->r[high];
        
        //④ 比較,從低位開始,找到比pivokey更大的值的下標位置;
        while (low < high && L->r[low] <= pivotkey)
            low++;
        
        //⑤ 將比樞軸值大的記錄交換到高端;
        //swap(L, low, high);
        //⑤ 採樣替換的方式將比樞軸值大的記錄替換到高端
        L->r[high] = L->r[low];
    }
    //將樞軸數值替換會L->r[low]
    L->r[low] = L->r[0];
    
    //返回樞軸pivokey 所在位置;
    return low;
}
//② 對順序表L的子序列L->r[low,high]做快速排序;
#define MAX_LENGTH_INSERT_SORT 7 //數組長度的閥值
void QSort2(SqList *L,int low,int high){
    int pivot;
    //if(low < high){
    //當high-low 大於常數閥值是用快速排序;
    if((high-low)>MAX_LENGTH_INSERT_SORT){
        //將L->r[low,high]一分爲二,算出中樞軸值 pivot;
        pivot = Partition(L, low, high);
        printf("pivot = %d L->r[%d] = %d\n",pivot,pivot,L->r[pivot]);
        //對低子表遞歸排序;
        QSort(L, low, pivot-1);
        //對高子表遞歸排序
        QSort(L, pivot+1, high);
    }else{
        //當high-low小於常數閥值是用直接插入排序
        InsertSort(L);
    }
}

//① 快速排序優化
void QuickSort2(SqList *L)
{
    QSort2(L,1,L->length);
}

#define N 9
int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, 排序算法\n");
    
    int i;
    int d[N]={-7,1,5,8,3,7,4,6,2};
    //int d[N]={9,8,7,6,5,4,3,2,1};å
    //int d[N]={50,10,90,30,70,40,80,60,20};
    SqList l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10;
   
    for(i=0;i<N;i++)
        l0.r[i+1]=d[i];
    
    l0.length=N;
    l1=l2=l3=l4=l5=l6=l7=l8=l9=l10=l0;
    
    printf("排序前:\n");
    print(l0);
    printf("\n");
    
    //10.快速排序
    printf("快速排序:\n");
    QucikSort(&l9);
    print(l9);
    printf("\n");
    
    //11.快速排序-優化
    printf("快速排序(優化):\n");
    QuickSort2(&l10);
    print(l10);
    printf("\n");
    
    
    printf("\n");
    return 0;
}
Hello, 排序算法
排序前:
-7,1,5,8,3,7,4,6,2

快速排序:
pivot = 1 L->r[1] = -7
pivot = 2 L->r[2] = 1
pivot = 6 L->r[6] = 5
pivot = 3 L->r[3] = 2
pivot = 5 L->r[5] = 4
pivot = 8 L->r[8] = 7
-7,1,2,3,4,5,6,7,8

快速排序(優化):
pivot = 1 L->r[1] = -7
pivot = 2 L->r[2] = 1
pivot = 6 L->r[6] = 5
pivot = 3 L->r[3] = 2
pivot = 5 L->r[5] = 4
pivot = 8 L->r[8] = 7
-7,1,2,3,4,5,6,7,8


Program ended with exit code: 0

 

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