1. 程式人生 > >八大排序———快速排序

八大排序———快速排序

  快速排序(Quicksort)是對氣泡排序的一種改進。

快速排序由C.A.R.Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,將整個排序過程可以遞迴進行,依次達到整個資料變成有序序列。

一:演算法思想

  假設要排序的陣列是A[0]......A[N-1],首先任意選取一個數據(通常情況下都是選擇陣列的第一個元素)作為關鍵資料,然後將所有比它小的數都放在它前面,所有比他大的數都放在後面,這個過程稱為一趟快速排序。它是一種不穩定的演算法。

一趟快速排序的思想是:

        ①:設定兩個遍歷變數,i和j。排序開始時 i=0;j=N-1

        ②:以第一個資料元素作為關鍵資料,賦值給key,即:key = A【0】;

        ③:從j開始向前搜尋,j--,找到第一個小於key的值A【j】,將A【j】和A【i】互換;

        ④:此時,再從i開始向後搜尋,i++,找到第一個大於key的A【i】,將A【i】和A【j】互換;

        ⑤:重複第3和4步,知道i=j;

二:過程演示

  

然後此時i=j那個位置的元素置為key 15,他的位置已經確定了。

然後在對這個位置之前的元素和之後的重複該過程。

三:程式碼分析

#include<stack>
#include<iostream>
using namespace std;

template<typename T>
int QSF(T arr[],int left,int right)
{
		T key = arr[left];
		while(left < right)
		{
				while(arr[right] >= key && left < right)//當我們的left和right元素相同時可能匯出先死迴圈問題
				{
						--right;
				}
				arr[left] = arr[right];
				while(arr[left] <= key && left < right)
				{
						++left;
				}
				arr[right] = arr[left];

		}
		if(left == right)
		{
				arr[left] = key;
				return left;
		}
		else
				return -1;
}
template<typename T>
void QuickSortfun(T arr[],int left,int right)
{
		if(left>=right)
				return;

		int index = QSF(arr,left,right);
		if(index == -1)
		{
				cout<<"the index is error:!"<<endl;
				return ;
		}

		QuickSortfun(arr,left,index-1);

		QuickSortfun(arr,index+1,right);

}
template<typename T>
void QuickSort(T arr[],int len)
{
		
		QuickSortfun(arr,0,len-1);//遞迴實現
}
int main()
{
		int arr[]={12,16,46,89,9,99,49,16,67,34,13,16};
		int len = sizeof(arr)/sizeof(arr[0]);
		QuickSort(arr,len);
 		for(int i=0;i<len;++i)
		{
				cout<<arr[i]<<" ";
		}
		cout<<endl;
		return 0;
}

三:時間複雜度和空間複雜度

  快速排序的平均時間複雜度為O(n*log n),最壞的時間複雜度為O(2^n)。

分析:

  1.最優情況:在最優的情況下,Partion每次都劃分的很均勻,如果排序n個關鍵字,那麼遞迴樹的深度就是[log2 n] +1,(每次都是除以2的關係。2^n = x => x =log2 n),每次Partion的迴圈次數(查詢index)為O(n),所以總的時間複雜度為O(n*log2 n)。空間複雜度為O(log2 n)。

  2.最壞情況:當資料是正序或者逆序的時間,每次劃分只得到比上一次換分少一個記錄的的子序列,所以要劃分n-1,也就是要遞迴n-1次,同時第i此劃分,需要經過n-i次的比較才能得到index的位置,所以此時的時間複雜度為O(n^2)。

四:演算法穩定性 

  是一種不穩定的排序演算法。

五:非遞迴實現——迴圈實現

#include<stack>
#include<iostream>
using namespace std;

template<typename T>
int QSF(T arr[],int left,int right)
{
		T key = arr[left];
		while(left < right)
		{
				while(arr[right] >= key && left < right)//當我們的left和right元素相同時可能匯出先死迴圈問題
				{
						--right;
				}
				arr[left] = arr[right];
				while(arr[left] <= key && left < right)
				{
						++left;
				}
				arr[right] = arr[left];

		}
		if(left == right)
		{
				arr[left] = key;
				return left;
		}
		else
				return -1;
}
template<typename T>
void QuickSortfunnotR(T arr[],int left,int right)
{
		if(left >= right )return;
		stack<int> s;
		s.push(right);//入棧,先入right
		s.push(left);
		int i = 0;
		int j = 0;
		while(!s.empty())
		{
			i = s.top();//出棧先出left
			s.pop();

			j = s.top();
			s.pop();
			int index = QSF(arr,i,j);
			if(j - index > 1)
			{
					s.push(j);
					s.push(index+1);
			}
			if(index - i > 1)
			{
					s.push(index-1);
					s.push(i);
			}
		}


}
template<typename T>
void QuickSort(T arr[],int len)
{
		QuickSortfunnotR(arr,0,len-1);//迴圈實現
	//	QuickSortfun(arr,0,len-1);//遞迴實現
}
int main()
{
		int arr[]={12,16,46,89,9,99,49,16,67,34,13,16};
		int len = sizeof(arr)/sizeof(arr[0]);
		QuickSort(arr,len);
 		for(int i=0;i<len;++i)
		{
				cout<<arr[i]<<" ";
		}
		cout<<endl;
		return 0;
}

六:快排的優化

  待更新。