快速排序
設計一個函數(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