1. 程式人生 > >分治與遞迴——快速排序

分治與遞迴——快速排序

       快速排序的基本思想可以這樣來理解:對一組待排序元素,選定其中一個元素x為基準,將小於x的元素移動到其左邊,將大於x的元素移動到其右邊,然後對於x左邊與右邊的序列進行上述的操作直至排序完成。

       該演算法時間複雜度最壞的情況出現在待排序列為正序或者逆序時。此時的時間複雜度為O(n2)

       平均時間複雜度為O(nlogn)

       原始碼如下:

#include<iostream>




using namespace std;





void Swap(int &a, int &b) 
{
 int t = a;
 a = b;
 b = t;
}




/*劃分函式*/
int Partition(int *array, int l, int r)
{
 int i = l, j = r + 1;
 int x = array[l];
 //比x小的元素交換到左邊區域
 //比x大的元素交換到右邊區域
 while (true)
 {
  while (array[++i] < x);
  while (array[--j] > x);
  if (i >= j)break;
  Swap(array[i], array[j]);
 }
 array[l] = array[j];
 array[j] = x;
 return j;
}
/*快速排序函式*/
void QuickSort(int *array,int l,int r)
{
 if (l < r) 
 {
  int t = Partition(array,l, r);
  QuickSort(array, l, t);
  QuickSort(array, t + 1, r);
 }
}




void main() 
{
 int temp[] = { 10,45,3,2,1,6,7,9,24,6 };
 cout << "排序前:" << endl;
 for(int i=0;i<10;i++)
 {
  cout << temp[i] << "\t";
 }
 cout << endl;
 QuickSort(temp, 0, 9);




 cout << "排序後:" << endl;
 for (int i = 0; i<10; i++)
 {
  cout << temp[i] << "\t";
 }
 cout << endl;
 system("pause");
}


         改進:如果每一次劃分都產生一邊是n-1個元素一邊是1個元素的情況那麼時間複雜度將變為O(n2),這顯然不是我們所期望的,如果每次劃分的兩個區域大小為n/2那麼時間複雜度將變為O(nlogn)。所以,快速排序演算法的效能取決於劃分的對稱性。上述的程式碼中始終是以待排序列的第一個元素作為劃分基準進行劃分的,通過修改劃分函式,可以設計出採用隨機選擇策略的快速排序演算法,即在快速排序演算法的每一步中當陣列還沒劃分時,在待排序列隨機選出一個劃分基準,這樣可以使劃分基準是隨機的,從而可以期望劃分是較對稱的

利用了隨機劃分的快速排序演算法(10萬個隨機數)

#include<iostream>
#include<fstream>
#include<time.h>

using namespace std;

/*功能:生成隨機數並存入檔案
 *這裡只是想試試這個方法
 *可以替換成別的產生隨機數的方法
 */
void Randmoize()							
{
	int m = 1000000;
	int c = 101;
	int b = 91;
	int n = 0;
	fstream fout;
	fout.open("RandomFile.txt", ios::out);
	for (int i = 0; i < 100000; i++)
	{
		n = (n * c + b) % m;				//線性同餘方程
		fout << n << "\n";
	};
	fout.close();
}

int temp[100000];										//存放待排序隨機數的陣列

/*讀取檔案中的隨機數並存入陣列*/
void ReadFile()											
{
	fstream fin;
	fin.open("RandomFile.txt", ios::in);
	for (int i = 0; i < 100000; i++)
	{
		fin >> temp[i];
	}
	fin.close();
}

void Swap(int &a,int &b)			
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}

/*劃分函式*/
int Partition(int *Array, int l, int r)		
{
	int i = l;
	int j = r + 1;
	int x = Array[l];
	while(true)								//將小於x的數放在其左邊,大於x的數放在右邊。
	{
		while (Array[++i] < x);
		while (Array[--j] > x);
		if (i >= j)break;
		Swap(Array[i], Array[j]);
	}
	Array[l] = Array[j];
	Array[j] = x;
	return j;
}

/*隨機分組*/
int RandomizedPartition(int Array[], int l, int r)			//隨機分組
{
	srand(time(NULL));
	int i = l + rand() % (r - l + 1);							//生成l~r之間的隨機數
	Swap(Array[i], Array[l]);									//將隨機得到的位置的值作為分組基準
	return Partition(Array, l, r);
}

/*快速排序函式*/
void QuickSort(int *Array, int l, int r)					
{
	if (l < r)
	{
		int q = RandomizedPartition(Array, l, r);
		QuickSort(Array, l, q - 1);
		QuickSort(Array, q + 1, r);
	}
}

void main()
{
	Randmoize();
	ReadFile();
	int l = 0, r = 99999;
	QuickSort(temp, l, r);

	fstream f;									//將排序好的序列儲存至另一個檔案
	f.open("SortedFile.txt", ios::out);
	for (int i = 0; i < 100000; i++)
	{
		f << temp[i] << "\n";
	}
	f.close();
}