C#實現(遞迴和非遞迴)快速排序和簡單排序

來源:互聯網
上載者:User

     本人因為最近工作用到了一些排序演算法,就把幾個簡單的排序演算法,想冒泡排序,選擇排序,插入排序,奇偶排序和快速排序等整理了出來,代碼用C#代碼實現,並且通過了測試。希望能給大家提供參考。

    1.冒泡排序

       冒泡排序,是指電腦的一種排序演算法,它的時間複雜度是O(n^2),雖然不及堆排序和快速排序時間複雜度為O(nlogn,底數為2),但是有兩個優點:1:編程複雜度低,很容易實現;2 是具有穩定性,這裡的穩定性是指源序列中相同元素的相對順序仍然保持到排序後的順序,而堆排序和快速排序都不具有穩定性。

     基本概念

         冒泡排序(BubbleSort)的基本概念:依次比較相鄰兩個數,小的在前,大的在後。在第一趟,首先比較第1個數和第2個數,小的放在前面,大的放在後面,然後比較第2個數和第3個數,小的在前,大的在後,如此繼續,直到比較最後兩個數,小的在前,大的在後,第一趟結束時,就把最大的數放在了最後。在第二趟,仍從第一對數開始比較(因為由於第2個數和第3個數的交換,使第1個數不再小於第2個數),將小數放前,大數放後,一直比較到倒數第二個數(倒數第一個數已經是最大的),第二趟結束,這樣在倒數第二個位置得到一個新的最大數,如此迴圈下去,重複以上過程,直至最終完成排序。

比如有一個數列10, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76

第一次排序後:10,2,4,33,6,12,34,55,66,43,23,65,1,345,61,76,31,43,76,456

第二次排序後:2,4,10,6,12,33,34,55,43,23,65,1,66,61,76,31,43,76,345,456

第三次排序後:2,4,6,10,12,33,34,43,23,55,1,65,61,66,31,43,76,76,345,456

第四次排序後:2,4,6,10,12,33,34,23,43,1,55,61,65,31,43,66,76,76,345,456

第五次排序後: 2,4,6,10,12,33,23,34,1,43,55,61,31,43,65,66,76,76,345,456

第六次排序後: 2,4,6,10,12,23,33,1,34,43,55,31,43,61,65,66,76,76,345,456

第七次排序後: 2,4,6,10,12,23,1,33,34,43,31,43,55,61,65,66,76,76,345,456

第八次排序後: 2,4,6,10,12,1,23,33,34,31,43,43,55,61,65,66,76,76,345,456

第九次排序後: 2,4,6,10,1,12,23,33,31,34,43,43,55,61,65,66,76,76,345,456

第十次排序後: 2,4,6,1,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

第十一次排序後:2,4,1,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

第十二次排序後:2,1,4,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

第十三次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

這樣經過13趟排序後這個序列就成為一個有序的數列。

具體實現代碼為:

       private static void BubbleSort(int[] R)
        {
            int len = R.Length;
            bool flag = false;
            for (int i = 0; i < len-1; i++)
            {
                flag = false;
                for (int j = 0; j < len - i-1; j++)
                {
                    if (R[j] > R[j + 1])
                    {
                        Swap(ref R[j], ref R[j + 1]);
                        flag = true;
                    }
                }
                if (!flag)
                {
                    break;
                }
            }
        }

       private static void Swap(ref int left, ref int right)
        {
            int temp = left;
            left = right;
            right = temp;
        }

 

2. 選擇排序

      每一趟從待排序的元素中選擇最小的(最大的)一個元素,順序放在已排好序的數列的最後,直到待排序的元素派完,選擇排序是不穩定的排序。

    基本概念

          具有n元素的數列可以進行n-1趟直接選擇排序得到有序結果,初始狀態有序區為空白,無序區為R[1...n]

          第1趟排序在無序區R[1...n]選擇關鍵字最小的元素R[k],將它與無序區的R[1] 進行交換,使R[1...1]和R[2...n]變為個增加為1新有序區,和無序區的元素個數減去1的新無序區。

         第i趟排序開始時,當前有序區和無序區分別為R[1..i-1]和R(1≤i≤n-1)。該趟排序從當前無序區中選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,

         使R[1..i]和R分別變  為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。 這樣,n個記錄的檔案的直接選擇排序可經過n-1趟直接選擇排序得到有序結果 .

         對於數列    10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76     

         第一次排序後:1,33,2,4,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76

         第二次排序後:  1,2,33,4,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76

         第三次排序後:1,2,4,33,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76

         第四次排序後:1,2,4,6,55,33,12,34,456,66,43,23,65,10,345,61,76,31,43,76

         第五次排序後:1,2,4,6,10,33,12,34,456,66,43,23,65,55,345,61,76,31,43,76

         第六次排序後:  1,2,4,6,10,12,33,34,456,66,43,23,65,55,345,61,76,31,43,76

         第七次排序後:  1,2,4,6,10,12,23,34,456,66,43,33,65,55,345,61,76,31,43,76

         第八次排序後:  1,2,4,6,10,12,23,31,456,66,43,33,65,55,345,71,76,34,43,76

         第九次排序後:  1,2,4,6,10,12,23,31,33,66,43,456,65,55,345,71,76,34,43,76

         第十次排序後:  1,2,4,6,10,12,23,31,33,34,43,456,65,55,345,71,76,66,43,76

         第十一次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,65,55,345,71,76,66,456,76

         第十二次排序後:  1,2,4,6,10,12,23,31,33,34,43,43,55,65,345,71,76,66,456,76

         第十三次排序後:  1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,345,456,76

        第十四次排序後:   1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,76,456,345

        第十五次排序後:   1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,76,345,456

       最終經過15次排序後成為有序的數列。

       具體實現代碼為:

        private static void SelectSort(int[] R)
        {
            int len = R.Length;
            int min = 0;
            for (int i = 0; i < len - 1; i++)
            {
                min = i;
                for (int j = i + 1; j < len - 1; j++)
                {
                    if (R[min] > R[j])
                    {
                        min = j;
                    }
                }
                Swap(ref R[i], ref R[min]);
            }
        }

 

3. 插入排序

        插入排序演算法是一種穩定的演算法,時間複雜度是O(n^2),適用於少量資料的排序。插入演算法的基本操作就是將一個資料插入到已經排好序的有序資料中,從而得到一個新的,個數加1的有序資料。插入演算法把要排序的數組分為兩部分:第一部分包含了數組的所有元素,但將最後一個元素除外,而第二部分就只包含這一個元素,在第一部分排序後,再把最後這個元素插入到此刻已是有序的一部分中。

   基本思想

         1:每次處理都是將無序序列的第一個元素和有序序列的元素從後面逐一比較,查到合適的插入位置,將該元素插入到有序序列的合適位置。

         2:從有序R[1]和無序R[2...n]開始進行排序。

         3:處理第i個元素時(i=2,3,…,n) ,數列{R1,R2,...Ri-1}都是有序的,而數列{Ri,Ri+1,...Rn}都是無序的,用Ri 與{R1,R2,...Ri-1}逐個比較,找到合適位置,將Ri插入,

         4:重複第三部,共進行n-i次插入處理,數組全部有序

         對於數列    10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76     

        第一次排序後:10,33,2,4,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

        第二次排序後:  2,10,33,4,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

        第三次排序後:  2,4,10,33,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

        第四次排序後:  2,4,10,33,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

        第五次排序後:  2,3,10,12,33,55,34,456,66,43,23,65,1,345,61,76,31,43,76

        第六次排序後:  2,3,10,12,33,34,55,456,66,43,23,65,1,345,61,76,31,43,76

        第七次排序後:  2,3,10,12,33,34,55,456,66,43,23,65,1,345,61,76,31,43,76

        第八次排序後:  2,3,10,12,33,34,55,66,456,43,23,65,1,345,61,76,31,43,76

        第九次排序後:  2,3,10,12,33,34,43,55,66,456,23,65,1,345,61,76,31,43,76

        第十次排序後:  2,3,10,12,23,33,34,43,55,66,456,65,1,345,61,76,31,43,76

        第十一次排序後: 2,3,10,12,23,33,34,43,55,65,66,456,1,345,61,76,31,43,76

        第十二次排序後: 1,2,3,10,12,23,33,34,43,55,65,66,456,345,61,76,31,43,76

        第十三次排序後: 1,2,3,10,12,23,33,34,43,55,65,66,345,456,61,76,31,43,76

        第十四次排序後: 1,2,3,10,12,23,33,34,43,55,61,65,66,345,456,76,31,43,76

        第十五次排序後: 1,2,3,10,12,23,33,34,43,55,61,65,66,76,345,456,31,43,76

        第十六次排序後: 1,2,3,10,12,23,31,33,34,43,55,61,65,66,76,345,456,43,76

        第十七次排序後: 1,2,3,10,12,23,31,33,34,43,43,55,61,65,66,76,345,456,76

        第十八次排序後: 1,2,3,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

       共十八次排序後,數組才是全部有序的。

      實現代碼為:

         private static void InsertSort(int[] R)
        {
            int len = R.Length;
            int j = 0;
            int temp = 0;
            for (int i = 1; i < len; i++)
            {
                temp=R[i];
                j=i-1;
                while (j >= 0 && temp < R[j])
                {
                    R[j + 1] = R[j];
                    j--;
                }
                R[j + 1] = temp;
            }
        }

 

4. 快速排序

           快速排序是對冒泡排序的一種改進,它的基本思想是:通過一趟排序將要排序的數列分成獨立的兩個部分,其中一部分的所有資料都比後一部分的所有資料都要小,然後再按此方法對這兩個部分分別進行快速排序,整個排序過程可以遞迴進行,以次達到整個數列變為有序。快速排序不是穩定的排序。

  演算法過程

         設要排序的數組為R[1...n],首先任意選取一個元素(通常選擇第一個元素)作為關鍵元素,然後把所有比它小的都放在前面,所有比它大的都放在後面,這個過程成為一趟快速排序。

         1. 設定兩個變數 low ,high,排序開始的時候low=0,high=n-1;

         2. 以第一個數組元素為關鍵資料key,即key = R[low];

         3. 從high開始往前搜尋,即由後開始向前搜尋,high=high-1,找到第一個小於key的值R[high], 並與R[low] 交換,

         4. 從low 開始向後搜尋,即由前開始向後搜尋,low=low+1,找到第一個大於key的值R[low],並於R[high]交換。

         5. 重複3,4.直到low=high.

            對於數列    10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76   

           初始關鍵資料key=10;

           第一次交換後:1, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76

           第二次交換後:  1, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76

           第三次交換後:   1, 6, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76

           第四次交換後:  1, 6, 2, 4, 55, 55, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76

          這樣low=high=4

           再把R[low]=key

          這樣第一次快速排序後數列就變為{1,6,2,4}10{55,12,34,456,66,43,23,65,33,345,61,76,31,43,76}  

          這樣再分別對{1,6,2,4}和{55,12,34,456,66,43,23,65,33,345,61,76,31,43,76}  分別進行快速排序,重複這個步驟,最終使整個數組都是有序的。

         具體實現代碼為:

          private static void QuickSort(int[] R, int low, int high)
        {
            int pivotLoc = 0;

            if(low<high)

             {
                  pivotLoc = Partition(R, low, high);
                  QuickSort(R, low, pivotLoc - 1);
                  QuickSort(R, pivotLoc + 1, high);

              }
        }

        private static int Partition(int[] R, int low, int high)
        {
            int temp = R[low];
            while (low < high)
            {
                while (low < high && temp <= R[high])
                {
                    high--;
                }
                R[low] = R[high];
                while (low < high && temp >= R[low])
                {
                    low++;
                }
                R[high] = R[low];
            }
            R[low] = temp;
            return low;
        }

    //快速非遞迴排序
        public static void QuickSort(int[] R, int Low, int High, Stack<int> stack)
        {
            int low = Low;
            int high = High;
            int temp = R[low];
            while (high > low)
            {
                while (low < high && temp <= R[high])
                {
                    high--;
                }
                if (high > low)
                {
                    R[low] = R[high];
                    R[high] = temp;
                }
                while (low < high && temp >= R[low])
                {
                    low++;
                }
                if (high > low)
                {
                    R[high] = R[low];
                    R[low] = temp;
                }
                if (low == high)
                {
                    if (Low < low - 1)
                    {
                        stack.Push(Low);
                        stack.Push(low - 1);
                    }
                    if (High > low + 1)
                    {
                        stack.Push(low + 1);
                        stack.Push(High);
                    }
                }
            }
        }

       測試代碼:

 static void Main(string[] args)

{

        int[] arry = new int[] { 10, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76 };
            Stack<int> s=new Stack<int>();
            s.Push(0);
            s.Push(arryk.Length - 1);
            while (s.Count > 0)
            {
                int low = s.Pop();
                int high = s.Pop();
                if (low > high)
                {
                    temp = low;
                    low = high;
                    high = temp;
                }
                QuickSort(arryk, low, high, s);             
            }      
            Console.ReadLine();

}

通過對10萬條隨機資料進行遞迴和非遞迴排序後發現,非遞迴方法的速度是遞迴方法速度的40倍左右。

5 . 一個無序的數組,如何通過一個函數取出最大值和最小值,要求時間複雜度最低和空間最少

  具體演算法如下:

        private static int[] GetMaxMin(int[] R)
        {         
            int len=R.Length;
            int min = R[0];
            int max = R[0];
            for (int i = 1; i < len;i++ )
            {
                if (min > R[i])
                {
                    min = R[i];
                }
                if (max < R[i])
                {
                    max = R[i];
                }
            }
            int[] res = new int[2];
            res[0] = min;
            res[1] = max;
            return res;

        }
6  對於已知數組,隨機儲存一百個數,把奇數放左邊,偶數放右邊,具體演算法如下:

        private static void SortNumber(int[] R)
        {
            int high = R.Length - 1;
            int low = 0;
            int temp = R[low];
            while (low < high)
            {
                while(low<high&&R[high]%2==0)
                {
                    high--;
                }
                R[low] = R[high];
                while (low < high && R[low] % 2 == 1)
                {
                   low++;
                }
                R[high] = R[low];
            }
            R[low] = temp;
        }

        7.二分尋找演算法 

                二分尋找演算法又叫折半尋找,優點是比較次數少,尋找速度快,平均效能好,缺點是給定的數組必須是有序的,且插入刪除困難,因此二分尋找使用與不經常變動而又尋找頻繁的有序表。 首先,假設數組是按照升序的有序表,將表中間位置的元素與給定要尋找的元素比較,如果相等,則尋找成功,否則利用中間位置將表分為前後兩個字表,如果中間位置記錄的元素大於給定的尋找的資料,在前面的字表中進行尋找,否則在後面的字表中進行尋找。重複以上過程,直到找到或沒有子表為止。

具體實現代碼如下:

       private static int BinarySearch(int[] R, int arg)
        {
            int low = 0;
            int high = R.Length - 1;
            while (low < high)
            {
                int middle = (low + high) / 2;
                if (arg == R[middle])
                {
                    return middle;
                }
                else if (arg < R[middle])
                {
                    high = middle - 1;
                }
                else
                {
                    low = middle + 1;
                }
            }
            return -1;
        }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.