快速排序

fushuxuan1發表於2024-04-20
/*
 * quickSort.cpp(快速排序)
 *
 *  Created on: 2012-4-21
 *      Author: jiyiqin
 *
 *  快速排序:
 *
 *	分治法:
 *		和歸併排序一樣,快速排序也是基於分治思想的。
 *	代價:
 *		時間複雜度,期望為o(n log n), 但是最壞可能達到o(n^2)
 *		空間複雜度,o(1),因為是基於交換元素的。
 *	穩定性:
 *		depends
 *	描述:
 *		選擇一個partitioner,然後兩個指標從頭尾各自開始掃描
 *		如果前面的比他大,停止,如果後面的比他小,停止,然後交換
 *
 *		迭代進行前半部分和後半部分(partitioner為分割點)
 */

#include <iostream>
using namespace std;

class QuickSort{
private:

	/**
	 * 特別注意:
	 * 這種交換方式在交換同一個記憶體的元素時,
	 * 會導致記憶體中的元素變為0。
	 * */
	void swap(int *a, int *b){
		//*a = *a + *b;
		//*b = *a - *b;
		//*a = *a - *b;
		int temp = *a;
		*a = *b;
		*b = temp;
	}
public:

	/**
	 * 選擇一個分割點,將a[low~high]分隔為兩部分
	 * 返回選擇的分割點最終所在位置
	 * 分隔點值:隨機化可以有效避免最壞時間複雜度
	 * 分隔點位置:最好在high處,在low處會麻煩一些,除非倒著掃描
	 *
	 * ###交換的思想:
	 *
	 * 這裡將小於x的元素和大於x的元素劃分開利用了
	 * 類似於(荷蘭國旗)的思想。
	 * 即用指標i指向第一個應該被交換到後面的元素(大於x)。
	 * 然後另外用j作為掃描一遍的掃描指標,如果掃描到小於
	 * 分割點x,則將其與a[i]交換(各取所需)。
	 *
	 * 這樣一遍下來,i一直向前(擴張),比x大的元素就會慢慢被
	 * (逼到)後面。掃描到a[high]的時候將其與第一個大於分割點
	 * 的元素a[i]交換即可將分隔點放到最終正確位置。
	 * 3,4,6,3,7,8,3,2,6,11,5
	 * */
	int partition(int a[], int low, int high){
		int pviot = a[high];	//最後一個元素作為分割點,否則會比較麻煩
		int p = low;			//指標p指向第一個不滿足小於pviot的元素

		//掃描一遍
		for(int j=low;j<high;j++){
			if(a[j] < pviot){
				swap(&a[p], &a[j]);
				p++;
			}
		}

		//將分割點與第一個不滿足小於pviot的元素交換
		swap(&a[p], &a[high]);
		return p;
	}

	/**
	 * 基於分治思想的快速排序
	 * */
	void quickSort(int a[], int low, int high){
		int p;

		//注意if的條件
		if(low < high){
			p = partition(a, low, high);	//find partition			
			quickSort(a, low, p-1);
			quickSort(a, p+1, high);
		}
	}
};

int main(){
	QuickSort qsort;
	int a[] = {12,2,16,-3,0,-1,4,10,20,6,18};

	//quickSort
	qsort.quickSort(a, 0, 10);
	for(int i=0;i<10;i++){
		cout<<a[i]<<" ";
	}
	cout<<endl;
	return 0;
}


相關文章