1. 程式人生 > >算法和數據結構~各位排序算法的介紹與實現(C#)

算法和數據結構~各位排序算法的介紹與實現(C#)

index per 歸並 一次 集中 div lag 合並 如何

排序是指將元素集合按照規定的順序排列。通常有兩種排序方法,升序排列和降序排列。例如,對整數集{5,2,7,1}進行升序排列,結果為{1,2,5,7},對其進行降序排列結果為{7,5,2,1}。總的來說,排序的目的是使數據能夠以更有意義的形式表現出來。雖然排序最顯著的應用是排列數據以顯示它,但它往往可以用來解決其他的問題,特別是作為某些已成型算法的一部分。
總的來說,排序算法分為兩大類:比較排序和線性時間排序。比較排序依賴於比較和交換來將元素移動到正確的位置上。令人驚訝的是,並不是所有的排序算法都依賴於比較。對於那些確實依賴於比較來進行排序的算法來說,它們的運行時間往往不可能小於O(nlg n)。對於線性時間排序,從它的名字就可以看出,它的運行時間往往與它處理的數據元素個數成正比,即為O(n)。遺憾的是,線性時間排序依賴於數據集合中的某些特征,所以我們並不是在所有的場合都能夠使用它。某些排序算法只使用數據本身的存儲空間來處理和輸出數據(這些稱為就地排序),而有一些則需要額外的空間來處理和輸出數據(雖然可能最終結果還是會拷貝到原始的內存空間中)。

技術分享
    /// <summary>
    /// 排序算法
    /// 作者:倉儲大叔
    /// 代碼來源:部分自寫,部分網上摘錄,都經過測試可以放心使用
    /// </summary>
    public class SortHelper
    {
        #region Public Methods
        /// <summary>
        /// 插入排序
        /// </summary>
        public static void InsertSort(List<int> list)
        {

            /*
             * 復雜度 O(n^2)
             * 插入排序從根本上來說,就是每次從未排序的數據集中取出一個元素,插入已排好序的數據集中。在以下所展示的實現中,兩個數據集都存放在data中,data是一塊連接的存儲區域。最初,data包含size個無序元素。隨著issort的運行,data逐漸被有序數據集所取代,直到issort返回(此時,data已經是一個有序數據集)。雖然實現插入排序用到連續的存儲空間,但它也能用鏈表來實現(並不是所有的排序都可以使用鏈表來實現),並且效率不差。
             */
            for (int j = 1; j < list.Count; j++)
            {
                int i = j - 1;
                int currnet = list[j];
                while (i >= 0 && currnet > list[i])
                {
                    list[i + 1] = list[i];
                    i--;
                }
                list[i + 1] = currnet;
            }
        }
        /// <summary>
        /// 快速排序
        /// </summary>
        /// <param name="list">目標數組</param>
        /// <param name="left">子表的起始位置</param>
        /// <param name="right">子表的終止位置</param>
        public static void QuickSort(List<int> list, int left, int right)
        {
            /*
           * 復雜度 O(nlg^n)
           * 描述 利用快速排序將數組data中的元素進行排序。數組中的元素個數由size決定。而每個元素的大小由esize決定。參數i和k定義當前進行排序的兩個部分,其值分別初始化為0和size-1。函數指針compare會指向一個用戶定義的函數來比較元素大小。其函數功能與issort中描述的一樣。當qksort返回時,data包含已排序的元素
           */
            if (left < right)
            {
                int i = Division(list, left, right);
                //對樞軸的左邊部分進行排序
                QuickSort(list, i + 1, right);
                //對樞軸的右邊部分進行排序
                QuickSort(list, left, i - 1);
            }
        }
        /// <summary>
        /// 歸並排序
        /// </summary>
        /// <param name="array">目標數組</param>
        /// <param name="first">子表的起始位置</param>
        /// <param name="last">子表的終止位置</param>
        public static void MergeSortFunction(List<int> array, int first, int last)
        {
            /*
             * 復雜度 O(nlg^n)
             * 描述 利用歸並排序將數組data中的元素進行排序。數組中的元素個數由size決定。而每個元素的大小由esize決定。參數i和k定義當前進行排序的兩個部分,其值分別初始化為0和size-1。函數指針compare會指向一個用戶定義的函數來比較元素大小。其函數功能與issort中描述的一樣。當mgsort返回時,data中包含已排序的元素。
             */
            if (first < last)   //子表的長度大於1,則進入下面的遞歸處理
            {
                int mid = (first + last) / 2;   //子表劃分的位置
                MergeSortFunction(array, first, mid);   //對劃分出來的左側子表進行遞歸劃分
                MergeSortFunction(array, mid + 1, last);    //對劃分出來的右側子表進行遞歸劃分
                MergeSortCore(array, first, mid, last); //對左右子表進行有序的整合(歸並排序的核心部分)
            }

        }
        /// <summary>  
        /// 計數排序  
        /// </summary>  
        /// <param name="arrayToSort">要排序的數組</param>  
        /// <param name="maxValue">數組的最大值加一</param>  
        /// <returns>計數排序後的結果</returns>  
        public static List<int> CountingSort(List<int> arrayA, int arrange)
        {
            /* 復雜度 O(n+k),n為要排序的元素的個數,k為data中最大的整數加1。
             * 計數排序是一種高效的線性排序,它通過計算一個集合中元素出現的次數來確定集合如何排列。不同於之前介紹的一些算法是基於比較的,計數排序不需要進行元素比較,而且它的運行效率要比效率為O(nlg n)比較排序高。 
             */

            int[] arrayResult = new int[arrayA.Count];
            int[] arrayTemp = new int[arrange + 1];
            for (int i = 0; i <= arrange; i++)
            {
                arrayTemp[i] = 0;
            }
            for (int j = 0; j < arrayA.Count; j++)
            {
                arrayTemp[arrayA[j]] += 1;
            }
            for (int k = 1; k <= arrange; k++)
            {
                arrayTemp[k] += arrayTemp[k - 1];
            }
            for (int m = arrayA.Count - 1; m >= 0; m--)
            {
                arrayResult[arrayTemp[arrayA[m]] - 1] = arrayA[m];
                arrayTemp[arrayA[m]] -= 1;
            }
            return arrayResult.ToList();
        }
        /// <summary>
        /// 冒泡排序
        /// </summary>
        /// <param name="arr"></param>
        public void EbullitionSort(List<int> arr)
        {
            /*
             * 復雜度O(n^2) 
             * 對1至n個記錄,在第i趟排序中設置標誌flag:=true,未排序的標誌。從下往上掃描,以j作為內層循環變量,共做n-i次比較。在第j趟比較中,若r[j+1]<r[j]則交換,並至flag為false。在一趟排序結束後,若flag為true,則終止排序。
             */
            int i, j, temp;
            bool done = false;
            j = 1;
            while ((j < arr.Count) && (!done))//判斷長度    
            {
                done = true;
                for (i = 0; i < arr.Count - j; i++)
                {
                    if (arr[i] > arr[i + 1])
                    {
                        done = false;
                        temp = arr[i];
                        arr[i] = arr[i + 1];//交換數據    
                        arr[i + 1] = temp;
                    }
                }
                j++;
            }
        }

        #endregion

        #region Private Methods
        /// <summary>
        /// 歸並排序的核心部分:將兩個有序的左右子表(以mid區分),合並成一個有序的表
        /// </summary>
        /// <param name="array"></param>
        /// <param name="first"></param>
        /// <param name="mid"></param>
        /// <param name="last"></param>
        private static void MergeSortCore(List<int> array, int first, int mid, int last)
        {

            int indexA = first; //左側子表的起始位置
            int indexB = mid + 1;   //右側子表的起始位置
            int[] temp = new int[last + 1]; //聲明數組(暫存左右子表的所有有序數列):長度等於左右子表的長度之和。
            int tempIndex = 0;
            while (indexA <= mid && indexB <= last) //進行左右子表的遍歷,如果其中有一個子表遍歷完,則跳出循環
            {
                if (array[indexA] <= array[indexB]) //此時左子表的數 <= 右子表的數
                {
                    temp[tempIndex++] = array[indexA++];    //將左子表的數放入暫存數組中,遍歷左子表下標++
                }
                else//此時左子表的數 > 右子表的數
                {
                    temp[tempIndex++] = array[indexB++];    //將右子表的數放入暫存數組中,遍歷右子表下標++
                }
            }
            //有一側子表遍歷完後,跳出循環,將另外一側子表剩下的數一次放入暫存數組中(有序)
            while (indexA <= mid)
            {
                temp[tempIndex++] = array[indexA++];
            }
            while (indexB <= last)
            {
                temp[tempIndex++] = array[indexB++];
            }

            //將暫存數組中有序的數列寫入目標數組的制定位置,使進行歸並的數組段有序
            tempIndex = 0;
            for (int i = first; i <= last; i++)
            {
                array[i] = temp[tempIndex++];
            }

        }

        /// <summary>
        /// 獲取按樞軸值左右分流後樞軸的位置
        /// </summary>
        /// <param name="list"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        private static int Division(List<int> list, int left, int right)
        {
            while (left < right)
            {
                int num = list[left]; //將首元素作為樞軸
                if (num > list[left + 1])
                {
                    list[left] = list[left + 1];
                    list[left + 1] = num;
                    left++;
                }
                else
                {
                    int temp = list[right];
                    list[right] = list[left + 1];
                    list[left + 1] = temp;
                    right--;
                }
            }
            return left; //指向的此時樞軸的位置
        }
        #endregion

    }
技術分享

算法和數據結構~各位排序算法的介紹與實現(C#)