1. 程式人生 > 其它 >C++實現快速排序演算法(遞迴法)

C++實現快速排序演算法(遞迴法)

技術標籤: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;
}

演示結果截圖:
在這裡插入圖片描述

參考書:紫皮資料結構課本教材