C++實現快速排序演算法(遞迴法)
快速排序是對氣泡排序的一種改進,又稱為分割槽交換排序,它是由託尼·霍爾(C.A.Hoare)提出並發展而來的。快速排序採用的是分治策略,它是目前已知的排序速度最快的一種排序方法。
由於在氣泡排序中記錄的比較和交換總是在相鄰的單元間進行的,記錄每次交換隻能向前或向後移動一個位置,故而比較和移動的總次數較多。而在快速排序中,記錄的比較和交換是從兩端向中間進行的,關鍵字較小的記錄可能會一次從後面單元交換到前面去,與之類似,關鍵字較大的記錄一次就能從前面單元交換到後面去,記錄移動的距離較遠,因而減小了總的比較次數和移動次數。
快速排序的基本思想是:通過一趟排序將待排序記錄分割槽成兩個獨立的部分,其中一部分記錄的關鍵字均小於等於另一部分記錄的關鍵字,再分別對這兩部分記錄進行下一趟排序,最後使整個記錄序列有序。
快速排序的排序過程具體如下。在待排序記錄序列中任取一個記錄R[i](通常可選取第1個記錄,稱記錄R[i]為參照記錄),以記錄R[i]的關鍵字Ki 為基準,將其他所有記錄關鍵字與Ki 進行比較,然後將小於Ki 的記錄排在R[i]之前,大於Ki 的記錄排在R[i]之後,這樣就以R[i]為分界點,將待排序記錄分成兩部分(也稱為兩個子序列),這個過程稱為分割槽。經過一趟快速排序後,這兩個部分及R[i]之間已經達到有序,如果R[i]之前的記錄及R[i]之後的記錄也都是有序的,則整個序列就達到了有序。繼續對分割槽後的各子序列按上述過程進行分割槽和排序,這樣重複下去,直到所有子序列只有一個記錄為止,由於一個記錄的序列當然可被視為是有序的,因而就不需要再分割槽了。當最後所有的子序列都只有一個記錄時,整個序列也就有序了,故排序結束。
由此可知,快速排序的關鍵是對待排序序列進行分割槽,以及對分割槽出的各個子序列再進行分割。下面介紹一種分割槽的簡單方法,這種方法是從序列的兩端開始交替掃描各個記錄,將關鍵字小於Ki 的記錄依次放到序列的前邊,將關鍵字大於Ki 的記錄從序列的最末端開始,依次放置到序列的後邊,直到掃描完所有的記錄為止。
在對待排序序列或子序列進行一次分割槽時,可按如下步驟進行。首先選取待排序序列中的第一個記錄,也可選取序列中的某個記錄,作為分割的基準,並將該元素賦給臨時變數temp。再設定兩個指標i和j分別指向序列的起始與最後位置,然後反覆進行如下兩項操作。
(1)將j逐漸減小,並逐次比較R[j].key與temp.key,直到發現一個R[j].key<temp.key為止,並將R[j]移到R[i]的位置上。這樣就完成了第一趟快速排序。
(2)將i逐漸增大,並逐次比較 R[i].key與temp.key,直到發現一個R[i].key>temp.key為止,並將R[i]移到R[j]的位置上。
將上述兩項操作交替進行,直到指標i與j指向同一個位置(即i=j)為止,此時將temp移到R[i]的位置上。
快速排序演算法描述如下。
void Quick_Sort(RecType R[],int left,int right)
{//用遞迴方法把R[left]至R[righ]的記錄進行快速排序
int i=left, j=right, k; //書本錯誤,這裡沒用到k。脫褲子放屁
RecType temp;
if(left<right)
{
temp=R[left];
while(i!=j)
{
while(j>i && R[j].key>=temp.key)
j--;
if (i<j)
{
R[i]=R[j];
i++;
} //若找到這樣的R[j],將R[j]存放到R[i]處
while(i<j&&R[i].key<=temp.key)
i++; //從左向右掃描,找第1個關鍵字大於temp.key的R[i]
if (i<j)
{
R[j]=R[i];
j--;
} //找到則將R[i] 存放到R[j] 處
} R[i]=temp; //將基準放入其最終位置
Quick_Sort(R,left,i-1); //對基準前面的記錄序列進行遞迴排序
Quick_Sort(R,i+l,right); //對基準後面的記錄序列進行遞迴排序
}
原始碼:
#include <iostream>
#include <cstdlib> //rand() 和 srand()的標頭檔案
#include <ctime> //time的標頭檔案
#define MAXSIZE 10 //巨集定義陣列最大容量
using namespace std;
void make_sorted(int * array) //隨機生成100以內的亂序整數
{ //這裡把array[0]留著當中轉站用
srand((unsigned int)time(NULL));
cout << "隨機生成的10個數為:";
for(int i = 1; i < MAXSIZE + 1; i++)
{
array[i] = rand() % 100;
cout << array[i] << " ";
}
cout << endl;
}
void quick_sort(int * array, int left, int right) //快速排序
{
int i = left, j = right, k;
if (left < right)
{
array[0] = array[left];
while (i != j)
{
while (j > i && array[j] >= array[0]) //從右往左尋找,遇到不符合的,j往前移
{
j--;
}
if (j > i) //滿足大前提條件且a[j]<a[i],把a[j]換到前面去,i再往後移一格
{
array[i] = array[j];
i++;
}
while (i < j && array[i] <= array[0]) //從左往右尋找,遇到不符合的,i往後移
{
i++;
}
if (i < j) //滿足大前提條件且a[i]<a[就],把a[i]換到後面去,j再往前移一格
{
array[j] = array[i];
j--;
}
}
array[i] = array[0]; //這時候a[o]裡面存的值已經找好了中間的位置,放進去就行(左邊都比a[0]小,右邊反之
quick_sort(array, left, i - 1); //這裡開始遞迴呼叫,左半區和右半區再慢慢排成有序
quick_sort(array, i + 1, right);
}
}
void print_quick_sort(int * array, int left, int right) //列印快速排序結果
{
quick_sort(array, left, right);
cout << "快速排序的結果為:";
for (int i = 1; i < MAXSIZE + 1; i++)
{
cout << array[i] << " ";
}
cout << endl;
}
int main()
{
int * array;
array = new int [MAXSIZE];
make_sorted(array);
print_quick_sort(array, 1, MAXSIZE);
cout << endl;
delete [] array;
return 0;
}
演示結果截圖:
參考書:紫皮資料結構課本教材