快速排序

1、快速排序

通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。


2、排序的過程

wKiom1ecofvy18fgAAA6kmo7ivo086.png-wh_50

wKioL1ecofyhfpmmAAA-0M-dQJU541.png-wh_50


3、代碼實現

三數取中法代碼:

//優化一:三數取中法,避免出現最壞的情況
int GetMidIndex(int* a,int left,int right)
{
	assert(a);
	int mid = left + (right- left)/2;
	if(a[left] > a[right])
	{
		if(a[mid] > a[left])
		{
			return left;
		}
		else
		{
			if(a[mid] > a[right])
				return mid;
			else
				return right;
		}
	}
	else//right大
	{
		if(a[mid] > a[right])
			return right;
		else//right 大
		{
			if(a[mid] > a[left])
				return mid;
			else
				return left;
		}
	}
}

快速排序的代碼:

int PartSort1(int* a,int left,int right)
{
	int mid = GetMidIndex(a,left,right);
	int key = a[mid];
    int begin = left;
    int end = right-1;

	swap(a[mid],a[right]);
    while(begin <end)
    { 
        while(begin <end && a[end] >=key)
            end--;
		 while(begin <end && a[begin] <key)
            begin++;

		 if(begin < end)
		swap(a[begin],a[end]);
    }
	if(a[begin] > a[right])
	{
		swap(a[begin],a[right]);
		return begin;
	}
	else
		return begin;

}
void QuickSort(int* a,int left,int right)
{
	//快速排序的第二種優化,將插入排序與快速排序結合
	assert(a);
	if(left >= right)
		return;
	if(right -left < 16)
	{
		InsertSort(a+left,right-left+1);
		return;
	}
	else
	{
	    int ret = PartSort1(a,left,right);
	    QuickSort(a,left,ret-1);
	    QuickSort(a,ret+1,right);
	}

}

另外兩種快速排序的方法:

//挖坑法
int PartSort2(int* a,int left,int right)
{
	int mid = GetMidIndex(a,left,right);
	int key = a[mid];
    int begin = left;
    int end = right;//初始時的坑
	swap(a[mid],a[right]);
	while(begin < end)
	{
		while(begin < end && a[begin] <= key)
			begin++;
		if(begin < end)
		{
			a[end] = a[begin];//begin的位置變爲坑
		}
		while(begin < end && a[end] >= key)
			end--;
		if(begin < end)
		{
			a[begin] = a[end];
		}
	}
	//跳出循環後,begin的位置爲坑,將key放入
	a[begin] = key;
	return begin;
}
//雙指針法
int PartSort3(int* a,int left,int right)
{
	int mid = GetMidIndex(a,left,right);
	int key = a[mid];
	swap(a[mid],a[right]);
	int cur = 0;
	int prev = -1;
	while(cur < right)
	{
		if(a[cur] < key && (++prev != cur))
			swap(a[cur],a[prev]);
		cur++;			
	}
	prev++;
	swap(a[prev],a[cur]);
	return prev;
}


4、時間複雜度

1)最好:O(N*logN)

在最好情況下,每次劃分所取的基準都是當前無序區的"中值"記錄,劃分的結果是基準的左、右兩個無序子區間的長度大致相等。總的關鍵字比較次數:O(NlogN)。


2)最壞:O(N*N)(key取得的值接近最大或最小)

最壞情況是每次劃分選取的基準都是當前無序區中關鍵字最小(或最大)的記錄,劃分的結果是基準左邊的子區間爲空(或右邊的子區間爲空),而劃分所得的另一個非空的子區間中記錄數目,僅僅比劃分前的無序區中記錄個數減少一個。時間複雜度爲O(N*N)。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章