資料結構與演算法C#版筆記–排序(Sort)-上

來源:互聯網
上載者:User

這裡討論的僅限於內部排序(即全部資料都在記憶體中,通過CPU運算處理元素排序),而且僅限順序表排序(即不討論鏈表,樹狀結構等結構的排序)

註:排序後的結果可以從小到大,或者從大到小,這隻是一個相反的處理而已,為方便起見,本文中的方法都是從小到大排序

1、直接插入排序(InsertOrder)

思路:從第二個元素開始向後遍曆,檢查本身(後面稱之為tmp)與前面相鄰元素的大小,如果發現前面的元素更大,則依次從近及遠(即倒序遍曆)檢查前面的所有元素,將比自身元素大的元素依次後移,這樣最終將得到一個空位,將tmp元素插在這個位置即可.

        /// <summary>        /// 直接插入排序法        /// </summary>        /// <param name="lst"></param>        static void InsertSort(int[] lst)        {            int _circleCount = 0;            //外迴圈從第二個元素開始從前向後遍曆            for (int i = 1; i < lst.Length; i++)            {                _circleCount++;                //Console.WriteLine("外迴圈i=" + i);                //如果發現某元素比前一個元素小                if (lst[i] < lst[i - 1])                {                    int tmp = lst[i];                    int j = 0;                    //則該元素前面的元素,從後到前遍曆,依次後移,直接找到應該插入的空檔在哪裡(這樣tmp元素就找到了自己的位置)                    for (j = i - 1; j >= 0 && tmp < lst[j]; j--)                    {                        //如果發現有比tmp小的元素,則將元素後移一位(從而把自身空出來,形成一個空檔,以方便如果前面還有更小的元素時,可以繼續向後面的空檔移動)                        lst[j + 1] = lst[j];                        _circleCount++;                        //Console.WriteLine("內迴圈i=" + i + ",內迴圈j=" + j);                    }                    //Console.WriteLine("j={0}", j);                    //運行到這裡時,j已經是空檔的前一個下標                    lst[j + 1] = tmp;                }            }            Console.WriteLine("InsertOrder共迴圈了{0}次", _circleCount);        }

點評:最好情況下,如果所有元素(N個)已經排好序了,則外迴圈跑N-1次,內迴圈一次也進不了,即0次,時間複雜度為O(N);最壞情況下,所有元素反序,外迴圈N-1次,內迴圈為i(i從1到N-1),時間複雜度為O(N*N);所以元素越有序列,該方法效率越高,其時間複雜度從O(N)到O(N*N)之間,此外,該方法是一種穩定排序。(註:若數組中有相同值的元素時,經過某方法排序後,這二個相同值的元素先後順序仍然不變,則稱這種排序方法為穩定的,反之為不穩定排序方法)

2、冒泡排序法(BubbleSort)

思路:從最後一個元素開始向前遍曆,依次檢查本元素與前面相鄰元素的大小,如果前面的元素更大,則交換位置,如此反覆,直到把自己前移到合適的位置(即 相當於後面的元素,通過這種比較,按照從小到大將不斷移動前面來,就象氣泡從下面向上冒一樣)

        /// <summary>        /// 冒泡排序法        /// </summary>        /// <param name="lst"></param>        static void BubbleSort(int[] lst)        {            int _circleCount = 0;//輔助用,可以去掉            int tmp;            for (int i = 0; i < lst.Length; i++)            {                for (int j = lst.Length - 2; j >= i; j--)                {                    if (lst[j + 1] < lst[j])                    {                        tmp = lst[j + 1];                        lst[j + 1] = lst[j];                        lst[j] = tmp;                    }                    _circleCount++;                }            }            Console.WriteLine("BubbleOrder共迴圈了{0}次", _circleCount);        }

點評:與插入排序法類似,最好情況是所有元素已經排好序,這樣只跑外迴圈,內迴圈因為if判斷不成立,直接退出;最壞情況是所有元素反序,外迴圈和內迴圈每次都要處理,因此時間複雜度跟插入排序法完全相同,同樣這也是一種穩定排序。

3、簡單選擇排序法 (SimpleSelectOrder)

思路:先掃描整個數組,找出最小的元素,然後跟第一個元素交換(這樣,第一個位置的元素就排好了),然後從第二個元素開始繼續掃描,找到第二小的元素,跟第二個元素交換(這樣,第二個位置的元素也排好了)...如此反覆

        /// <summary>        /// 簡單選擇排序法        /// </summary>        /// <param name="lst"></param>        static void SimpleSelectSort(int[] lst)        {            int _circleCount = 0;//輔助用            int tmp = 0;            int t = 0;            for (int i = 0; i < lst.Length; i++)            {                t = i;                //內迴圈,找出最小的元素下標                for (int j = i + 1; j < lst.Length; j++)                {                    if (lst[t] > lst[j])                    {                        t = j;                    }                    _circleCount++;                }                //將最小元素[下標為t]與元素i互換                tmp = lst[i];                lst[i] = lst[t];                lst[t] = tmp;            }            Console.WriteLine("SimpleSelectSort共迴圈了{0}次", _circleCount);        }

點評:跟冒泡法很類似,不過應該注意到,這裡的元素交換操作是在內迴圈外,即不管如何這個交換操作是省不了的,所以其時間複雜度均為O(N*N),同樣這也是一個穩定排序。

4、快速排序(QuickOrder)

思路:以數組中間的元素做為分界線(該元素稱為支點),掃描其它元素,比支點小的放在左側,比支點大的放在右側,這樣就把數組分成了二段(即做了一次粗放的大致排序),然後對每一段做同樣的處理(即二段變四段,4段變8段...),直到最後每一段只有一個元素為止(沒錯,該方法是一個遞迴調用)

        /// <summary>           /// 快速排序           /// </summary>           /// <param name="arr">待排序數組</param>           /// <param name="left">數組第一個元素索引Index</param>           /// <param name="right">數組最後一個元素索引Index</param>           static void QuickSort(int[] arr, int left, int right)        {            //左邊索引小於右邊,則還未排序完成               if (left < right)            {                //取中間的元素作為比較基準,小於他的往左邊移,大於他的往右邊移                   int middle = arr[(left + right) / 2];                //因為while中要做++與--的操作,所以這裡先將i,j各自換外擴張一位                int i = left - 1;                int j = right + 1;                while (true)                {                    while (arr[++i] < middle) ;//如果前半部的元素值本身就比支點小,則直接跳過                    while (arr[--j] > middle) ;//如果後半部的元素值本身就比支點大,則直接跳過                    //因為前半段是向後遍曆,而後半段是向前遍曆,所以如果二者碰到了,                    //則說明所有元素都被掃過了一遍,完成退出                    if (i >= j)                     {                        break;                    }                    //經過前面的處理後,如果發現有放錯位置的元素,則將二者對換                    int tmp = arr[i];                    arr[j] = arr[i];                    arr[i] = tmp;                }                //經過上面的while迴圈後,元素已被分成左右二段(左段小於支點,右段大於支點)                //遞迴調用,處理左段                QuickSort(arr, left, i - 1);                //遞迴調用,處理右段                QuickSort(arr, j + 1, right);            }        }

點評:每次從中間分成二段,然後再中分為二段,如此反覆...這跟二叉樹很相似(每次分段,相當於樹中的某個節點分成二叉),最好情況下所有元素已經排好序,最終樹的左右分支數大致相同(即左右分支長度大致相同),所以分解次數為樹的高度log2N,而最壞情況下,所有元素反序,這時分解得到的樹相當於一個單右支二叉樹(即一個右分支超級長,沒有左分支的怪樹),即時間複雜度範圍為nLog2N 至 N*N。此外,快速排序是一種不穩定的排序(從代碼就能看出來,即使是二個相同值的節點,在分段過程中,也有可能被交換順序)

本來想將堆排序與歸併排序一起寫在這篇文章裡的,今天看了看堆排序,還有點小複雜,完全可以另起一篇詳解原理了,下篇將專門學習堆排序及歸併排序。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.