快速排序的三種實現方法 (C++)

Lazyboy_Chen7發表於2018-05-08

快速排序的中心思想

       快速排序利用的是分治思想,將一個大陣列的排序劃分為多個小陣列的排序,最後進行合併便是排序的結果。

      首先,需要從陣列中選擇一個主元,通常為陣列的第一個元素或最後一個元素(好操作)。接下來的工作就是要將陣列中的其他元素與主元進行對比,小於主元的元素放在主元的左邊,大於主元的元素放在主元的右邊。

      例如有陣列 A[begin...end] 經過上述步驟後會得到A[begin...q-1]A[q]A[q+1...end]

      其中A[q]為主元,子陣列 A[begin...q-1] 的所有元素小於主元,子陣列A[q+1...end] 的所有元素大於主元。

      此時,能確定的就是A[q]的位置,並且該位置就是最終排序後A[q]的位置,不會再變。

      接下來要做的就是讓兩個子陣列A[begin...q-1], A[q+1...end]重複上述步驟,直到每個子陣列只剩一個元素,此時就是最終排序完成的陣列。


      中午突然發現忘掉了快速排序的具體實現過程,下午趕快找空閒時間寫一次。

      快速排序有很多種方法,首先我們要了解的是快速排序創始人 C. A. R. Hoare 的實現方法。

一. 快速排序1

      比如有陣列{3,8,4,9,2,7,1},選擇3為主元,有兩個變數i,j 分別從陣列頭尾向中間滑動,每當j從尾開始找到小於主元的元素時停止,換i從頭查詢大於主元的元素,找到兩個元素後交換兩個元素的位置,直到i和j相等。(也可以用相反的方式,最終得到逆序的陣列)

       例如{3,8,4,9,2,7,1},主元為3,j從尾搜尋直到A[j]=1停止,i從頭搜尋直到A[i]=8停止,交換位置。

          →{3,1,4,9,2,7,8},接下來,j會一直搜尋直到A[j]=2,i搜尋到A[i]=4,交換位置。

          →{3,1,2,9,4,7,8},之後,j會搜尋到j=i,此時交換主元和位置i的元素,也就是3和2。

          →{2,1,3,9,4,7,8}   這便是經過一次排序操作後的結果,主元3左邊的子陣列{2,1}全部小於主元,右邊的子陣列{9,4,7,8}全部大於主元。之後再對子陣列進行相同的操作,直到最終排序完成。

二. 快速排序2

      這種排序方式是演算法導論第三版書中的方法,與第一種方法類似(其實都差不多,思路相同實現方式不同而已)。

      同樣使用{3,8,1,9,2,7,4},選擇4為主元,有兩個變數i,j 用來維持一段大於主元或小於主元的陣列A[i+1,j],最後將主元與A[i+1]交換。

        比如有{3,8,1,9,2,7,4},主元為4,令i+1指向3,j指向3,j向後移動,每當遇到小於主元的數便會與位於i+1的元素交換,直到最後,此時i到j之間所有元素均大於主元,此時交換主元與i處的元素。

        例如{3,8,1,9,2,7,4},主元為4,i與j指向3,i+1後移指向8,j後移直到1,此時此時交換1和8.

           →{3,1,8,9,2,7,4},之後i不變,用來控制大於主元陣列的頭部,j後移直到A[j] = 2,交換2和8.

           →{3,1,2,9,8,7,4},此時i+1指向9,之後直至結束沒有變化,交換i+1和主元。

           →{3,1,2,4,8,7,9},這便是經過一次排序操作後的結果,主元4左邊的子陣列{3,1,2}全部小於主元,右邊的子陣列{8,7,9}全部大於主元。之後再對子陣列進行相同的操作,直到最終排序完成。(過程中i與j之間的元素全部大於主元)

三.快速排序3

        這種排序方式是上課時講到的方法,這種方式主元不再是最後才進行移動。而是在比較過程中移動。

        比如有{3,8,1,9,2,7,4},令主元為3,有兩個變數i與j,分別從頭尾向中間進行掃描。這種方法是令j從尾向前掃描,知道遇到比主元小的元素,此時交換該元素與主元;之後令i從頭開始掃描,直到遇到比主元大的值,交換該值與主元,最終得到結果便是一個元素均大於主元的子陣列和一個元素均小於主元的子陣列,並且此時主元所在的位置就是最終排序後該元素應在的位置。

        例如{3,8,1,9,2,7,4},主元為3,i指向頭,j指向尾,j開始向前掃描,直到j指向2,交換2和3.

           →{2,8,1,9,3,7,4},之後i從頭開始掃描,直到i指向8,交換8和3.

           →{2,3,1,9,8,7,4},之後j從上次j掃描的位置繼續掃描,直到j=1,交換1和3.

           →{2,1,3,9,8,7,4},直至結束不再變化。這就是經過一次排序後的結果,主元3左邊元素均小於3,右邊元素均大於3。之後再多兩邊的子陣列進行相同的操作,直到排序完成。



        下面是這三種方式的實現程式碼.

#include <iostream>
using namespace std;

int len = 0;		//陣列長度

/**************************************    輸出函式    ********************************************/
void _show(const int a[])
{
	for(int i=0;i<len;i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
}
/**************************************    交換次序函式  ********************************************/
void swap(int *a,int i,int j)
{
	int temp;
	temp = a[i];
	a[i]= a[j];
	a[j] = temp;
}
/**************************************    快速排序1   ********************************************/
int _partition(int a[], int p, int r)
{
	int x = a[r];
	int i = p-1;
	for(int j=p;j<=r-1;j++)
	{
		if(a[j]<=x)
		{
			i=i+1;
			swap(a,i,j);
		}
	}
	swap(a,i+1,r);
	return i+1;
}
void _firstsort(int a[],int first,int last)
{
	int q;
	if(first<last)
	{
		q = _partition(a,first,last);
		_firstsort(a,first,q-1);
		_firstsort(a,q+1,last);
	}
}
/**************************************    快速排序2   ********************************************/
int _hoare(int a[], int p, int r)
{
	int x = a[p];
	int i = p;
	int j = r + 1;

	while(1)
	{
		while(a[--j]>x);
		while(a[++i]<x);

		if(i<j)
			swap(a,i,j);
		else
			break;
	}
	a[p] = a[j];
	a[j] = x;
	return j;
}
void _secondsort(int a[],int first,int last)
{
	int q;
	if(first<last)
	{
		q = _hoare(a,first,last);
		_secondsort(a,first,q-1);
		_secondsort(a,q+1,last);

	}
}
/**************************************    快速排序3   ********************************************/
int _coursep(int a[], int p, int r)
{
	int u = p;
	int d = r;
	while(u<d)
	{
		while(a[u]<a[d]&&u<d)
			u++;
		swap(a,u,d);
		while(a[d]>a[u]&&u<d)
			d--;
		swap(a,u,d);
	}
	return u;
}
void _thirdsort(int a[],int first,int last)
{
	int q;
	if(first<last)
	{
		q = _coursep(a,first,last);
		_thirdsort(a,first,q-1);
		_thirdsort(a,q+1,last);
	}
}

/**************************************     整理輸出形式  ********************************************/
void _first(int a[],int first,int last)
{
	cout << "******************************************" << endl;
	cout << "未排序序列:  ";
	_show(a);
	_firstsort(a,first,last);
	cout << "排序後序列:  ";
	_show(a);
	cout << "******************************************" << endl;
}
void _second(int a[],int first,int last)
{
	cout << "******************************************" << endl;
	cout << "未排序序列:  ";
	_show(a);
	_secondsort(a,first,last);
	cout << "排序後序列:  ";
	_show(a);
	cout << "******************************************" << endl;
}
void _third(int a[],int first,int last)
{
	cout << "******************************************" << endl;
	cout << "未排序序列:  ";
	_show(a);
	_thirdsort(a,first,last);
	cout << "排序後序列:  ";
	_show(a);
	cout << "******************************************" << endl;
}


/**************************************     MAIN      ********************************************/
int main()
{
	unsigned int flag = 0;
	unsigned int num = 0;
	cout << "快速排序測試......" << endl << endl;
	
	cout << "輸入陣列長度: ";
	cin >> len;
	int *arr = new int [len];
	
	cout << "輸入陣列元素: ";
	for(int i=0;i<len;i++)
	{
		cin >> arr[i];
	}
	
	while(1)
	{
		int *a = new int [len];
		for(int i = 0; i<len; i++)
		{
			a[i] = arr[i];
		}
		cout << "三種快速排序,選擇一種(1,2,3, 4退出)" << endl;
		cin >> flag;
		while(flag<1||flag>4)
		{
			cout << "輸入錯誤,重新輸入: ";
			cin >> flag;
		}
		switch(flag){
			case 1: _first(a,0,len-1);break;
			case 2: _second(a,0,len-1);break;
			case 3: _third(a,0,len-1);break;
			case 4: return 0;
			default: cout << "未知錯誤" << endl;
		}
		delete[] a;
	}
	delete[] arr;
	return 0;
}

       本來是想寫在小本子上記錄下來,後來琢磨著就乾脆寫到這裡吧,希望對演算法的初學者們有一個較好的引路作用(希望沒有誤人子弟)。

       快速排序的解釋,包括這段稚嫩的程式碼,其中一定存在沒有解釋清楚的地方,或者說不足之處,歡迎看到這篇文章的各位能夠提出寶貴意見。


       轉載註明出處哦:https://blog.csdn.net/lazyboy_/article/details/80242736



相關文章