C# 排序算法

前言:算法

排序算法是咱們編程中遇到的最多的算法。目前主流的算法有8種。編程

  平均時間複雜度從高到低依次是:數組

     冒泡排序(o(n2)),選擇排序(o(n2)),插入排序(o(n2)),堆排序(o(nlogn)),測試

     歸併排序(o(nlogn)),快速排序(o(nlogn)), 希爾排序(o(n1.25)),基數排序(o(n))優化

申明:如下排序所有針對數組{ 25, 1, 5, 2, 9, 11, 2, 4 };   全部測試使用備註,只是爲了讓用戶根據結果看得更加明白,理解以後可刪除。ui

1、冒泡排序spa

思想:從數組第一位開始,每一個元素和它下一位比較,將大的換到後面,即每一輪循環以後能夠肯定一個位置。提升效率(可定義一個標記,若是一輪循環以後沒有發生交換直接結束).net

代碼:3d

   static void maopao()
        {
            int[] a = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; 
            bool sign = false;
            for (int i = 0; i < a.Length - 1; i++)
            {
                for (int j = 0; j < a.Length - i - 1; j++)
                {
                    if (a[j] > a[j+1])
                    {
                        outPuts(a, "交換以前");//測試使用
                        Console.Write(String.Format("    {0:D2}<-交換->{1:D2}   ", a[j], a[j + 1]));//測試使用
                        int b = a[j];
                        a[j] = a[j + 1];
                        a[j + 1] = b;
                        sign = true;
                        outPuts(a, "交換以後");//測試使用
                        Console.WriteLine();//測試使用
                    }
                }
                if (!sign) break;
            }
            Console.WriteLine();//測試使用
            outPuts(a, "最後數據");
            Console.ReadKey();
        }

        private static void outPuts(int[] a, string str)
        {
            Console.Write(str + ":");
            foreach (var item in a)
            {
                Console.Write(item + " ");
            }
        }

 

結果:指針

 

2、選擇排序

對冒泡排序進行優化,由上結果能夠看到25連續交換屢次,那麼如何實現一次循環只交換一次就能夠肯定一個位置呢?

思想:對於第一趟,搜索整個數組,尋找出最小(或最大此處以最小爲例即從小到大排序)的,而後放置在數組的0號位置;對於第二趟,搜索數組的n-1個記錄,尋找出最小的(對於整個數組來講則是次小的),而後放置到數組的第1號位置。在第i趟時,搜索數組的n-i+1個記錄,尋找最小的記錄(對於整個數組來講則是第i小的),而後放在數組i-1的位置(注意數組以0起始)。

代碼:

  private static void xuanze()
        {
            int[] a = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 };
            for (int i = 0; i < a.Length - 1; i++)
            {
                int sign = i;
                for (int j = i + 1; j < a.Length; j++)
                {
                    if (a[sign] > a[j])
                    {
                        sign = j;
                    }
                }
                if (sign != i)
                {
                    outPuts(a, "交換以前");//測試使用
                    Console.Write(String.Format("    {0:D2}<-交換->{1:D2}   ", a[i], a[sign]));//測試使用
                    int b = a[i];
                    a[i] = a[sign];
                    a[sign] = b;
                    outPuts(a, "交換以後");//測試使用
                    Console.WriteLine();//測試使用
                }
            }
            Console.WriteLine();//測試使用
            outPuts(a, "最後數據");
            Console.ReadKey();
        }

        private static void outPuts(int[] a, string str)
        {
            Console.Write(str + ":");
            foreach (var item in a)
            {
                Console.Write(item + " ");
            }
        }

 

結果:

 

3、插入排序

插入排序是一種對於有序數列高效的排序。很是聰明的排序。只是對於隨機數列,效率通常,交換的頻率高。

思想:數組下標1開始,和前面下標爲0的數據做比較,若是下標0的數據大於(或小於即從大到小排序)下標1的數據則後移,下標1的數據插入到0的位置,不然插入當前位置。數組下標m開始,和因此前面數據做比較,即下標爲n(m-1>=n>=0)的數據做比較,若是下標n的數據大於(或小於即從大到小排序)下標m的數據則後移,直到n=-1,將下標爲m獲得數據插入到下標爲0的位置,不然插入當前位置,

代碼:

 private static void charu()
        {
            int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 };
            for (int i = 1; i < data.Length; i++)
            {
                int d = data[i];
                bool result = true;//標記,表示已經比較到第一個位置
                for (int j = i - 1; j >= 0; j--)
                {
                    if (data[j] > d)
                    {
                        outPuts(data, "移動以前");//測試使用
                        Console.Write(String.Format("    從下標{0}開始  {1}<-移動->{2}   ",i, j, j+1));//測試使用
                        data[j + 1] = data[j];
                        outPuts(data, "移動以後");//測試使用
                        Console.WriteLine();//測試使用
                    }
                    else
                    {
                        outPuts(data, "插入以前");//測試使用
                        Console.Write(String.Format("    從下標{0}開始  數據{1}<-插入到->{2}   ", i, d, j + 1));//測試使用
                        data[j + 1] = d;
                        result = false;
                        outPuts(data, "插入以後");//測試使用
                        Console.WriteLine();//測試使用
                        break;
                    }
                }
                if (result)
                {
                    outPuts(data, "插入以前");//測試使用
                    Console.Write(String.Format("    數據{0}<-插入到->{1}   ", d, 0));//測試使用
                    data[0] = d;
                    outPuts(data, "插入以後");//測試使用
                    Console.WriteLine();//測試使用
                }
            }
            Console.WriteLine();//測試使用
            outPuts(data, "最後數據");
            Console.ReadKey();
        }

        private static void outPuts(int[] a, string str)
        {
            Console.Write(str + ":");
            foreach (var item in a)
            {
                Console.Write(item + " ");
            }
        }

 

 //方法二
private static void charu2(int[] data)
        {
            int j;
            for (int i = 1; i < data.Length; i++)
            {
                int d = data[i];
                for (j = i - 1; j >= 0 && data[j] > d; j--)
                {
                    data[j + 1] = data[j];
                }
                data[j + 1] = d;
            }
        }

 

結果:

 

 

4、快速排序

快速排序是一種高效排序。它包含了「分而治之」以及「哨兵」的思想。

思想:從數組中挑選一個數(通常爲第一個數據)做爲「哨兵」,使比它小的放在它的左側,比它大的放在它的右側。

 

 

 說明:25爲哨兵,定義變量保存,0位置爲待處理位置,從right向前找直到找到比哨兵小的,將其放入到待處理位置,left++,並設置當前爲待處理位置,從left開始向後找比哨兵大的放入待處理位置,right--,並設置當前爲待處理位置。直到left>right結束,此時第一個哨兵位置肯定。並以哨兵爲點,將數組分爲兩段分別繼續遞歸實現該方法。

代碼:

     private static void kuaisu(int[] data, int left, int right)
        {
            if (left >= right) return;
            int x = data[left];
            int i = left;
            int j = right;
            try
            {
                while (i < j)
                {
                    while (i < j && data[j] >= x)
                    {
                        j--;
                    }
                    if (i == j) break;
                    outPuts(data, "移動以前");//測試使用
                    Console.Write(String.Format("    {0}<-移動到->{1}   ", j, i));//測試使用
                    data[i++] = data[j];
                    outPuts(data, "移動以後");//測試使用
                    Console.WriteLine();//測試使用
                    while (i < j && data[i] <= x)
                    {
                        i++;
                    }
                    if (i == j) break;
                    outPuts(data, "移動以前");//測試使用
                    Console.Write(String.Format("    {0}<-移動到->{1}   ", i, j));//測試使用
                    data[j--] = data[i];
                    outPuts(data, "移動以後");//測試使用
                    Console.WriteLine();//測試使用
                }
                outPuts(data, "移動以前");//測試使用
                Console.Write(String.Format("    數據{0}<-移動到->{1}  數據區間{2}--{3} ", x, i,left,right));//測試使用
                data[i] = x;
                outPuts(data, "移動以後");//測試使用
                Console.WriteLine();//測試使用
                kuaisu(data, left, i - 1);
                kuaisu(data, i + 1, right);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        private static void outPuts(int[] a, string str)
        {
            Console.Write(str + ":");
            foreach (var item in a)
            {
                Console.Write(item + " ");
            }
        }

 

結果:

 

5、歸併排序

使用遞歸方法。

思想:將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。

那麼如何肯定一個子序列有序呢?固然子序列個數爲1時天然有序。因此將數組分爲兩段,一直分段遞歸下去,直到數組長度爲1返回,此時將其歸併直到結束。

歸併操做的工做原理以下:
第一步:申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
第二步:設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
重複步驟3直到某一指針超出序列尾
將另外一序列剩下的全部元素直接複製到合併序列尾

代碼:

int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 };
guibing(data, 0, data.Length - 1);
outPuts(data, "最後數據");
Console.ReadKey();

 

        private static void guibing(int[] data, int left, int right)
        {
            if (left < right)
            {
                int mid = (left + right) / 2;
                guibing(data, left, mid);
                guibing(data, mid + 1, right);
                arrayAdd(data, left, mid, right);
            }
        }

        private static void arrayAdd(int[] data, int left, int mid, int right)
        {
            int[] d = new int[right - left + 1];
            int i = left;
            int j = mid + 1;
            int k = 0;
            while (i <= mid && j <= right)
            {
                if (data[j] < data[i]) d[k++] = data[j++];
                else d[k++] = data[i++];
            }
            while (i <= mid)
            {
                d[k++] = data[i++];
            }
            while (j <= right)
            {
                d[k++] = data[j++];
            }
            i = left;
            for (k = 0; k < d.Length; k++)
            {
                outPuts(data, "賦值以前");//測試使用
                Console.Write(" ");//測試使用
                data[i++] = d[k];
                outPuts(data, "賦值以後");//測試使用
                Console.Write(String.Format("    賦值下標位置範圍{0}--{1}  臨時數組:",left,right));//測試使用
                foreach (int f in d) //測試使用
                {
                    Console.Write(f + " ");
                }
                Console.WriteLine();//測試使用
            }
        }

        private static void outPuts(int[] a, string str)
        {
            Console.Write(str + ":");
            foreach (var item in a)
            {
                Console.Write(item + " ");
            }
        }

 

 

結果:

 

 

6、希爾排序

希爾排序是插入排序的一種更高效的改進版本。

思想:希爾排序是把記錄按下標的必定增量分組,對每組使用直接插入排序算法排序,隨着增量逐漸減小,每組包含的關鍵詞愈來愈多,當增量減至1時,整個數列恰被分紅一組,算法便終止。

增量算法有:http://www.javashuo.com/article/p-bhzgywko-bv.html

本文以:Hibbard 增量序列爲例

代碼:

int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 };
xier(data);
        private static void xier(int[] data)
        {
            List<int> garArry = new List<int>();
            int m = 0;
            while (Math.Pow(2,m) - 1 <= data.Length / 2)
            {
                m++;
                garArry.Add((int)Math.Pow(2, m) - 1);
            }
            for (int y = garArry.Count - 1; y >= 0; y--)
            {
                int gap = garArry[y];
                int j;
                //比較次數
                for (int i = gap; i < data.Length; i++)
                {
                    int d = data[i];
                    for (j = i - gap; j >= 0 && data[j] > d; j -= gap)
                    {
                        outPuts(data, "移動以前");//測試使用
                        Console.Write(String.Format("   {0}<-移動到->{1}  步長{2}  ", j, j + gap, gap));//測試使用
                        data[j + gap] = data[j];
                        outPuts(data, "移動以後");//測試使用
                        Console.WriteLine();//測試使用
                    }
                    outPuts(data, "移動以前");//測試使用
                    Console.Write(String.Format("   數據{0}<-移動到->{1}  步長{2}  ", d, j + gap, gap));//測試使用
                    data[j + gap] = d;
                    outPuts(data, "移動以後");//測試使用
                    Console.WriteLine();//測試使用
                }
            }
            outPuts(data, "最後數據");
        }

        private static void outPuts(int[] a, string str)
        {
            Console.Write(str + ":");
            foreach (var item in a)
            {
                Console.Write(item + " ");
            }
        }

 

結果:

 

後續添加更多排序方法

相關文章
相關標籤/搜索