C#快速排序演算法
今天重溫了下排序演算法,包括氣泡排序法和直接排序法,這些都比較簡單,只是快速排序法比較難,於是重點研究了下。
先說一說原理:快速排序法是採用遞迴的方式對待排序的數列進行若干次的操作,每次操作使得被操作的數列部分以某個元素為分界值分成兩部分,一部分小於該分界值,另一部分大於該分界值.該分界值一般被稱為”樞軸”. 一般先以左邊第一個數作為分界值,將數列按該分界值分成左右兩部分,左邊部分小於該分界值,右邊部分大於該分界值,然後再對左右兩部分做重複的操作,直到最後完成排序。
以數列 14,11,25,37,9,28 為例,詳細描述執行一趟快速排序的演算法:
1.選擇待排序數列的樞軸,一般以數列的首元素作為樞軸.此數列中,我們選擇首元素14作為樞軸,nPivot = 14.
2.設定兩個指標 i 和 j ,分別指向數列的首元素和尾元素. i 指向首元素14, j 指向尾元素28.示意圖如下:
3.向前移動尾指標 j ,使其指向從數列尾部算起首個小於樞軸(即14)的元素,並將該元素置換到頭指標 i 指向的位置._nArray[i] =_nArray[j].示意圖如下:
首次執行該操作時 i 指標指向處的值實際上就是樞軸的值,此處的操作可以理解為 i 指標指向處的值已在之前被置換到樞軸中,此時, i 指向處已經是一個空位,在此時用找到的小於樞軸的元素填在此處.
4,向後移動頭指標 i ,使其指向從數列頭部算起首個大於樞軸(即14)的元素,並將該元素置換到尾指標 j 指向的位置._nArray[j] =_nArray[i].示意圖如下:
此處同樣可以理解為 j 指標指向處的值已在上一步操作中置換了出去. j 處已是一個空位.
5,如此重複執行步驟3和步驟4,直至 i==j 時結束該迴圈.
6,退出了該迴圈後, i 與 j 必定指向同一位置.在該位置的前部元素,其值均小於樞軸.而在該位置的後部元素,其值均大於樞軸.顯而易見,此時 i 和 j 同時指向的位置就應該是樞軸的”新家”._nArray[i]=nPivot.如下圖:
至此,一趟排序結束.待排序數列的首元素將該數列分成了比其小和比其大的兩部分.如下圖:
接著,我們對這一大一小兩部分子數列執行相同的排序操作.
如此”遞迴”,直至對整個數列完成排序操作.
以下是c#實現程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 快速排序
{
using System;
public static class Program
{
public static void Main()
{
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
const int z = 10000000;
//隨機生成一千萬個數。
int[] a = new int[z];
Random random = new Random();
for (int i = 0; i < z; i++)
{
a[i] = random.Next(0, z);
}
watch.Start();//計時器開始。
QuickSort(a, 0, z - 1);
watch.Stop();//計時器結束。
for (int i = z - 1000; i < z; i++)
{
Console.WriteLine(a[i]);
}
string time = watch.ElapsedMilliseconds.ToString();
Console.Write("排序所用時間 :" + " " + time + " ms");
Console.Write("\r\n");
Console.ReadKey();
}
private static void QuickSort(int[] a, int low, int high)
{
if (low >= high)
{
return;
}
int pivot = QuickSortOnce(a, low, high);//輸出每一次排序。
//對樞軸左端進行排序。
QuickSort(a, low, pivot - 1);
//對樞軸右端進行排序。
QuickSort(a, pivot + 1, high);
}
private static int QuickSortOnce(int[] a, int low, int high)
{
//將首個元素作為樞軸。
int pivot = a[low];
int i = low, j = high;
while (i < j)
{
//從右往左,尋找首個小於povit的元素。
while (a[j] >= pivot && i < j)
{
j--;
}
//執行到此,j一定指向從右端起首個小於或等於povit的元素。執行替換。
a[i] = a[j];
//從左往右,尋找首個大於povit的元素。
while (a[i] <= pivot && i < j)
{
i++;
}
////執行到此,j一定指向從右端起首個大於或等於povit的元素。執行替換。
a[j] = a[i];
}
//退出while迴圈,執行至此,必定是i==j的情況。i(或j)指向的既是樞軸的位置,定位該趟排序的樞軸並將該位置返回。
a[i] = pivot;
return i;
}
}
}