1. 程式人生 > >快速排序 C++版

快速排序 C++版

一、實現原理看下面程式碼中的註釋。

二、實現方法及測試程式碼如下:

#include <iostream>

using namespace std;

/******************************
快速排序:選一個基準數將原始陣列劃分成兩個子陣列第一個子陣列是小於基準數的數
第二個子陣列是大於基準數的數。然後再對兩個子陣列進行第歸操作,直到排序完成。
基數的選擇可以選擇最左邊、最右邊、中間數或者三者中的中位數,以選中位數為最優。
優點:1、速度快 2、移動資料少
缺點:1、邏輯複雜 2、不穩定
演算法時間複雜度:O(nlog(n)~n^2) 空間複雜度:O(n)+輔助空間
******************************/

// 方法一
template<typename T>
void quick_sort(T data[],int first,int last)
{
    int lower = first+1,upper = last;
    swap(data[first],data[(first+last)/2]); // 選定中間的數為基數,並把基數與第一個數交換位置
    T bound = data[first];
    while(lower<=upper)
    {
        while(data[lower] < bound) // 尋找比基數大的數
        {
            lower++;
        }
        while(bound<data[upper])// 尋找比基數小的數
        {
            upper--;
        }
        if(lower<upper)
        {
            swap(data[lower++],data[upper--]);// 把左邊比基數大的和右邊比基數小的數交換
        }
        else
        {
            lower++; // 跳出while
        }
    }
    swap(data[upper],data[first]);
    if(first < upper-1)
    {
        quick_sort(data,first,upper-1);
    }
    if(upper+1 < last)
    {
        quick_sort(data,upper+1,last);
    }
}

template<typename T>
void quickSort(T data[],int n)
{
    int i,max;
    if(n<2)
    {
        return;
    }

    // 預處理,把最大的數放到最右邊
    for(i = 1,max = 0;i<n;i++)
    {
        if(data[max]<data[i])
        {
            max = i;
        }
    }
    swap(data[n-1],data[max]); // 把最大的數放到最右邊
    quick_sort(data,0,n-2); // 快排
}

// 方法二
template<typename T>
void quickSort1(T data[],int first,int last)
{
    if(first>=last) return;

    int lower = first+1;
    int upper = last;
    T base = data[first]; // 取最左邊的數為基數

    while(lower<=upper) // 必須帶等號,否則有錯誤
    {
        while(data[lower]<base && lower<upper) // 防止基數取的是最大值,導致程式非正常中斷
        {
            lower++;
        }
        while(data[upper]>base)
        {
            upper--;
        }
        if(lower<upper)
        {
            swap(data[lower++],data[upper--]);
        }
        else
        {
            lower ++;
        }
    }
    swap(data[upper],data[first]);// 把基準數放到找到的中間位置中
    if(first<upper-1)
    {
        quickSort1(data,first,upper-1);
    }
    if(upper+1<last)
    {
        quickSort1(data,upper+1,last);
    }
}

// 方法三 取最左邊最右邊和中間數三個數中的中位數為基準數
template<typename T>
void quickSortMid(T data[],int first,int last)
{
    if(first>=last) return;
    int lower = first,upper=last,mid=(first+last)/2;
    int min = data[first]<data[mid] ? first:mid; // 求第一個數和中間的數中的最小的數值的索引
    int midIndex = data[last]>min ? last:min; // 求最小的數和最後一個數中兩者中最大的即得到三者中的中位數索引
    T base = data[midIndex];
    while(lower<=upper)
    {
        while(data[lower]<base)
        {
            lower++;
        }
        while(data[upper]>base)
        {
            upper--;
        }
        if(lower<upper)
        {
            swap(data[lower++],data[upper--]);
        }
        else
        {
            break;
        }
    }
    swap(data[upper],data[midIndex]);
    if(first<upper-1)
    {
        quickSort1(data,first,upper-1);
    }
    if(upper+1<last)
    {
        quickSort1(data,upper+1,last);
    }
}

int main(int argc, char *argv[])
{
    int tempArr[] = {0,4,3,5,6,7,9,8,2,1};
    int arrSize = sizeof(tempArr)/sizeof(tempArr[0]);
    cout << "arrSize=" << arrSize << endl;
    for(int i=0; i<arrSize; i++)
    {
        cout << tempArr[i];
    }
    cout << endl;
    //quickSort(tempArr,arrSize);
    //quickSort1(tempArr,0,arrSize);
    quickSortMid(tempArr,0,arrSize);

    for(int i=0; i<arrSize; i++)
    {
        cout << tempArr[i];
    }
    cout << endl;
    cout << "Hello World!" << endl;
    return 0;
}

三、測試結果:
在這裡插入圖片描述