快速排序也叫分區排序,其基本思想是在特定範圍內對於某個基準值,將小於這個基準值的元素全部移到這個值的前面,大於這個值的元素全部移到這個值的後面,然後再對前後範圍的元素遞歸進行分區,最終得到一個有序序列。快速排序的時間複雜度爲O(nlgn),空間複雜度爲O(lgn),當數組元素數量較大時,快速排序要比其他排序都要好,但是當數量級較小時,快速排序的性能可能沒有其他排序好。
下面給出快排的實現:
#include <iostream>
using namespace std;
#include <cassert>
#include <ctime>
#include <cstdlib>
template <typename T>
struct Less
{
bool operator()(T &left, T &right)const
{
return left < right;
}
};
template <typename T>
struct Greater
{
bool operator()(T &left, T &right)const
{
return left > right;
}
};
template <typename T>
void SelectMid(T *array, int left, int right) //三數取中函數
{
assert(NULL != array && left >= 0 && right >= 0);
if(right - left <= 1)
return;
int mid = left + ((right-left)>>1);
int buf[3] = { left, mid, right-1 };
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2-i; j++)
{
if(Greater<T>()(array[buf[j]], array[buf[j+1]]))
swap(buf[j], buf[j+1]);
}
}
if(array[buf[1]] != array[right-1])
swap(array[buf[1]], array[right-1]);
}
template <typename T>
int Partition1(T *array, int left, int right) //分區函數1,也是最容易想到的
{
assert(NULL != array && left >= 0 && right >= 0);
assert(right - left > 1);
int start = left;
int tail = right-1;
T key = array[right-1];
while(start < tail)
{
while((Less<T>()(array[start], key)||array[start]==key) && start < tail)
start++;
while((Greater<T>()(array[tail], key)||array[tail]==key) && start < tail)
tail--;
if(start < tail)
swap(array[start], array[tail]);
}
if(start != right-1)
swap(array[start], array[right-1]);
return start;
}
template <typename T>
int Partition2(T *array, int left, int right) //分區函數2,也稱爲挖坑法
{
assert(NULL != array && left >= 0 && right >= 0);
assert(right - left > 1);
int start = left;
int tail = right-1;
T key = array[right-1];
while(start < tail)
{
while((Less<T>()(array[start], key)||array[start]==key) && start < tail)
start++;
if(Greater<T>()(array[start], key))
array[tail] = array[start];
while((Greater<T>()(array[tail], key)||array[tail]==key) && start < tail)
tail--;
if(Less<T>()(array[tail], key))
array[start] = array[tail];
}
if(start < right)
array[start] = key;
return start;
}
template <typename T>
int Partition3(T *array, int left, int right) //分區函數3
{
assert(NULL != array && left >= 0 && right >= 0);
assert(right - left > 1);
int start = left-1;
int tail = left;
T& key = array[right-1];
while(tail < right-1)
{
start++;
tail++;
while(Less<T>()(array[start], key) && tail < right-1)
{
start++;
tail++;
}
while(Greater<T>()(array[tail], key) && tail < right-1)
tail++;
if(tail < right && Greater<T>()(array[start], array[tail]))
swap(array[start], array[tail]);
}
return start;
}
template <typename T>
void _quickSort(T *array, int left, int right)
{
assert(NULL != array && left >= 0 && right >= 0);
if(right - left <= 1)
return;
SelectMid(array, left, right); //利用三數取中法將基準元素移到最右邊
int keysub = Partition3(array, left, right);
_quickSort(array, left, keysub);
_quickSort(array, keysub+1, right);
}
template <typename T>
void QuickSort(T *array, const int size)
{
assert(NULL != array && size > 0);
if(size == 1)
return;
_quickSort(array, 0, (int)size);
}
測試函數:
void test7()
{
int arr[100] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
srand((unsigned int)time(0));
for(int i = 0; i < sz; i++) //Assign values with random numbers
{
arr[i] = rand() % sz;
}
for(int i = 0; i < sz; i++) //print array
cout << arr[i] << " ";
cout << endl << endl << endl << "sort:" << endl;
QuickSort(arr, sz); //sort
for(int i = 0; i < sz; i++) //print array
cout << arr[i] << " ";
cout << endl;
for(int i = 1; i < sz; i++) //check that the sort is correct
{
if(Less<int>()(arr[i], arr[i-1]))
cout << "sort error! " << arr[i] << endl;
}
}
三個分區函數實現算法不同,達到效果一樣。因此這裏就僅貼一種分區函數的測試結果圖: