1. 程式人生 > >使用C++實現快速排序QuickSort

使用C++實現快速排序QuickSort

參考了weiss的《資料結構與演算法分析》的C++描述第三版。

快速排序原理其實很簡單,是一個遞迴的過程。首先確定一個樞紐元,然後把大於樞紐元的元素放在左邊,把小於樞紐元的元素放在右邊。然後再對左右兩邊的子序列不斷的重複這個操作(確定樞紐元,然後把大小元素歸類),直到子序列中的元素為0個或1個的時候結束。

需要注意的兩個地方:第一個是樞紐元的選取。最好不要直接選擇序列的第一個元素作為樞紐元,因為在待排序列較為有序的時候,可能會一直處於最壞的情形。常見的選取方法是三數取中(詳細的可見下面的程式)。

第二個需要注意的地方是如何處理等於樞紐元的元素。對於從兩邊往中間走的遊標i和j來說,如果遇到等於樞紐元的元素,就應該讓i和j停止。

程式如下:

#include<iostream>
#include<vector>
#include<random>
#include<ctime>
#include<iterator>
#include<algorithm>
using namespace std;

/*
* 快速排序通過遞迴實現,因此該函式為驅動函式
*/
template<typename Comparable>
void quickSort(vector<Comparable> & a)
{
	quickSort(a, 0, a.size() - 1);
}

/*
* 通過“三數選中”的方法選擇樞紐元
* 找到樞紐元后,放在right-1的位置上
*/
template<typename Comparable>
const Comparable & median3(vector<Comparable> &a, int left, int right)
{
	//從對left,center,right位置上的三個數進行排序
	int center = (left + right) / 2;
	if (a[center] < a[left])
		swap(a[left], a[center]);
	if (a[right] < a[left])
		swap(a[right], a[left]);
	if (a[right] < a[center])
		swap(a[right], a[center]);

	//此時left、center、right位置上的數從小到大排序,且center位置上的元素為樞紐元
	//現在把center上的樞紐元放在right-1 的位置上
	swap(a[center], a[right - 1]);
	
	return a[right - 1];

}
/*
 快速排序主要的函式
 a表示待排的向量
 left表示子序列的最左邊元素下標
 right表示子序列的最右邊元素的下標
*/
template<typename Comparable>
void quickSort(vector<Comparable> & a, int left, int right)
{
	if (left + 10 < right)
	{
		Comparable pivot = median3(a, left, right);
		int i = left;
		int j = right - 1;
		while (1)
		{
			while (a[++i] < pivot);
			while (a[--j] > pivot);
			//因為如果i和j遇到等於樞紐元的元素,就讓i和j都停止
			if (i < j)
				swap(a[i], a[j]);
			else
				break;
		}
		swap(a[i], a[right - 1]);//把樞紐元放回在相應的位置
		quickSort(a, left, i - 1);//把小於樞紐元的集合排序
		quickSort(a, i + 1, right);//把大於樞紐元的集合排序
	}
	else
	{
		insertionSort(a, left, right);
	}
	
}


/*
 在快速排序遞迴的時候,如果向量長度小於10就用插入排序
*/
template<typename Comparable>
void insertionSort(vector<Comparable> & a, int left, int right)
{
	for (int p = left + 1; p <= right; ++p) // 從第二個數開始  
	{
		Comparable tmp = a[p];
		int j = p;
		for (; j > left && a[j - 1] > tmp; --j)
			a[j] = a[j - 1];
		a[j] = tmp;
	}
}

/*輸出向量*/
template<typename T>
void printVector(vector<T> & v)
{
	copy(v.cbegin(), v.cend(), ostream_iterator<T>(cout, " "));
	cout << endl;
}

int main()
{
	vector<int> source;
	uniform_int_distribution<int> u(0, 10);
	default_random_engine e(static_cast<unsigned int>(time(0)));
	for (int i = 0; i < 31; i++)
	{
		source.push_back(u(e));
	}

	cout << "排序前:" << endl;
	printVector(source);

	quickSort(source);

	cout << "排序後:" << endl;
	printVector(source);

	return 0;
}

結果如圖(以含有多個相同元素的序列為例)