1. 程式人生 > >C#快速排序演算法

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;






        }

    }
}