C#12種順序排序

 

這篇主要寫關於順序排序的十二種算法,也是我有關算法的第一帖。主要是寫,對每種算法的理解與測試。程序員

速度測試,主要根據一千、一萬、五萬、百萬這 四種。速度紀錄仍是用Stopwatch 這個類。使用隨機數Random生成隨機的集合。算法

其中數量五萬左右的小數量排序,使用快速排序,速度最快。大數量百萬左右使用鴿巢排序,速度最快。廢話很少說,接下來上代碼。數組

 

第一種:冒泡排序app

冒泡排序我相信是每一個程序員,都會學到的一種比較排序算法。很是簡單,經過屢次重複比較每對相鄰元素,並按規定的順序交換他們,最終把數列進行排序。dom

public static IList<int> BubbleSort(IList<int> list)
        {
            try
            {
                //獲取集合數量,比較排序,因此取倒數第二個
                int n = list.Count - 1;
                //大方向從前日後,一直到倒數第二個
                for (int i = 0; i < n; i++)
                {
                    //小方向從後往前,一直到大方向的索引
                    for (int j = n; j > i; j--)
                    {
                        //強轉比較類型,從最後往前比較一位
                        if (((IComparable)list[j - 1]).CompareTo(list[j]) > 0)
                        {
                            //利用優先級
                            list[j - 1] = list[j] + (list[j] = list[j - 1]) * 0;
                        }
                    }
                }
                return list;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

 

能夠看到,是兩個循環,大方向是從0到最後,小方向是從後往前。從後往前分別比較先後的數字,數字小的往前。性能

這種方法,是最慢的方法。由於只是一個一個比較,尾部小數問題嚴重影響速度。下面,上測試結果測試

一萬就5秒了,十萬和百萬,就不測試了。總而言之,很是慢。大數據

 

第二種:雙向冒泡ui

雙向冒泡是在冒泡排序的基礎上由兩個方向同時進行。只是解決了尾部小數問題,仍是比較排序算法。效率也不高。spa

public static IList<int> BiDerectionalBubleSort(IList<int> list)
        {
            try
            {
                //獲取集合數量
                int limite = list.Count;
                int st = -1;
                bool swapped = false;
                do
                {
                    swapped = false;
                    st++;
                    limite--;
                    //從左開始往右循環
                    for (int j = st; j < limite; j++)
                    {
                        //強轉排序類型比較,若是左邊比右邊大
                        if (((IComparable)list[j]).CompareTo(list[j + 1]) > 0)
                        {
                            list[j] = list[j + 1] + (list[j + 1] = list[j]) * 0;
                            swapped = true;
                        }
                    }
                    //從右開始往左循環
                    for (int j = limite - 1; j >= st; j--)
                    {
                        //強轉排序類型比較,若是左邊比右邊大
                        if (((IComparable)list[j]).CompareTo(list[j + 1]) > 0)
                        {
                            list[j] = list[j + 1] + (list[j + 1] = list[j]) * 0;
                            swapped = true;
                        }
                    }
                } while (st < limite && swapped);
                return list;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

首先是定義集合總數與-1。分別表明兩個循環的方向,而後使用do while,進行初步循環。

在do while裏面,分別對定義的變量,進行增減操做。一直到相交爲止。定義兩個方向的循環,而後就行先後比較,交換位置。

由於終究也是比較性排序,因此效率也不是很高。咱們看一下

 

第三種:桶排序

桶排序顧名思義,就是把數列劃分紅若干個桶的一種算法。屬於分佈排序算法。在每一個桶內各自進行排序,每一個桶內各自排序方式不限。

public static IList<int> BucketSort(IList<int> list)
        {
            int max = list[0];
            int min = list[0];
            //找集合中,最小值與最大值
            for (int i = 0; i < list.Count; i++)
            {
                if (((IComparable)list[i]).CompareTo(max) > 0)
                {
                    max = list[i];
                }

                if (((IComparable)list[i]).CompareTo(min) < 0)
                {
                    min = list[i];
                }
            }
            //定義一個足夠大的容器。由於是最大值-最小值。因此確定是足夠裝下全部集合。
            //注意事項:數組數量溢出
            ArrayList[] holder = new ArrayList[max - min + 1];

            //讓數組變成二維數組
            for (int i = 0; i < holder.Length; i++)
            {
                holder[i] = new ArrayList();
            }
            //把集合的數據,付給二維數組
            for (int i = 0; i < list.Count; i++)
            {
                holder[list[i] - min].Add(list[i]);
            }
            int k = 0;
            //循環容器
            for (int i = 0; i < holder.Length; i++)
            {
                //判斷是否有值
                if (holder[i].Count > 0)
                {
                    //從新給list進行賦值操做
                    for (int j = 0; j < holder[i].Count; j++)
                    {
                        list[k] = (int)holder[i][j];
                        k++;
                    }
                }
            }

            return list;
        }

首先第一步就是建立一個桶,也就是一個交叉數組(數組的數組)。那麼咱們找集合中,最大與最小,來建立一個可以徹底保存進去的集合。

而後循環進行交叉數組初始化操做。

接着遍歷一遍集合,holder[list[i] - min].Add(list[i]); 這句話是關鍵,把集合的值,看成數組的索引,進行Add添加。由於是二維數組,因此相同的數據,再多也沒事。

最後一步就簡單了,循環遍歷而後給list,進行復制操做。由於已經把list的值,放到桶裏面了,因此操做數據,不會受到影響。

其實這也算是,插入排序算法。只不過聲明這種很是大的容器是很消耗內存的。並非很推薦這種方法。咱們看一下性能

 

第四種:梳排序

梳排序中,是保持間距並不斷減小的過程。開始的時候間距設定爲列表長度,而後每一次都會除以損耗因子(通常爲1.3)。間距能夠四捨五入,不斷重複,直到間距變爲1。最後在進行一次冒泡排序。

 public static IList<int> CombSort(IList<int> list)
        {
            //獲取集合數量
            int gap = list.Count;
            int swaps = 0;

            do
            {
                //計算遞減率,必須大於1
                gap = (int)(gap / 1.3);
                if (gap < 1)
                {
                    gap = 1;
                }
                int i = 0;
                swaps = 0;
                do
                {
                    //每次循環1與另外一個數進行調換,直到循環尾部爲止
                    if (((IComparable)list[i]).CompareTo(list[i + gap]) > 0)
                    {
                        list[i] = list[i + gap] + (list[i + gap] = list[i]) * 0;
                        swaps = 1;
                    }
                    i++;
                } while (!(i + gap >= list.Count));
            } while (!(gap == 1 && swaps == 0));
            return list;
        }

首先計算遞減率,集合總數除以損耗因子,遞減率必須大於1。

從0開始 與 間隔值繼續比較,調換位置。一直到間隔位置大於集合總數。

而且每次進行間隔遞減,每次間隔都除以1.3。

其實重點也是比較排序,只不過是進行間隔排序基礎上。性能也是比較好的。

 

 第五種:圈排序

圈排序是一種不穩定的排序算法,是一種理論上最優的比較算法。他的思想是要把數列分解爲圈,能夠分別旋轉獲得排序結果。

與其餘排序不一樣的是,元素不會被放入數組的任何位置,若是這個值在正確位置,則不動。不然只會寫一次便可。

public static IList<int> CycleSort(IList<int> list)
        {
            //循環每個數組
            for (int cycleStart = 0; cycleStart < list.Count; cycleStart++)
            {
                int item = list[cycleStart];
                int pos = cycleStart;
                do
                {
                    int to = 0;
                    //循環整個數組,找到其相應的位置
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (i != cycleStart && ((IComparable)list[i]).CompareTo(item) < 0)
                        {
                            to++;
                        }
                    }
                    if (pos != to)
                    {
                        while (pos != to && ((IComparable)item).CompareTo(list[to]) == 0)
                        {
                            to++;
                        }
                        int temp = list[to];
                        list[to] = item;
                        item = temp;
                        pos = to;
                    }
                } while (cycleStart != pos);
            }
            return list;
        }

 

首先進行從前日後的循環。獲取不一樣位置的數據,當獲取到數據之後,會循環整個數組找到其相應的位置。而後進行位置插入。

看一下,具體的性能。對於很是雜亂無章的序列來說,真的好慢。

 

第六種:堆排序

堆排序是從數據集構建一個數據堆,而後提取最大元素,放到有序數列末尾。而後從新構造新的數據堆,一直到沒有數據爲止。屬於插入排序。

public static IList<int> HeapSort(IList<int> list)
        {
            //循環由於每次都能取出最大和最小,因此循環次數折中
            for (int i = (list.Count - 1) / 2; i >= 0; i--)
            {
                Adjust(list, i, list.Count - 1);
            }
            for (int i = list.Count - 1; i >= 1; i--)
            {
                list[i] = list[0] + (list[0] = list[i]) * 0;
                Adjust(list, 0, i - 1);
            }
            return list;
        }

public static void Adjust(IList<int> list, int i, int m)
        {
            int temp = list[i];//獲取該標識值
            int j = i * 2 + 1;//獲取對應尾部標識
            while (j <= m) //循環直到標識 <= 總數
            {
                if (j < m) //尾部標識 小於 總數
                {
                    //若是左邊小於右邊,右邊標識加一位
                    if (((IComparable)list[j]).CompareTo(list[j + 1]) < 0)
                    {
                        j = j + 1;
                    }
                }
                if (((IComparable)temp).CompareTo(list[j]) < 0)
                {
                    //交換位置
                    list[i] = list[j];
                    i = j;
                    j = 2 * i + 1;
                }
                else
                {
                    //結束循環
                    j = m + 1;
                }
            }
            list[i] = temp;
        }

 

看一下性能

 

第七種:插入排序

插入排序的原理是構造一個有序數列,對未排序的數據,從後向前掃描,找到相應的位置並插入。須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。

public static IList<int> InsertionSort(IList<int> list)
        {
            for (int i = 1; i < list.Count; i++)
            {
                int val = list[i];
                int j = i - 1;
                bool done = false;
                do
                {
                    if (((IComparable)list[j]).CompareTo(val) > 0)
                    {
                        list[j + 1] = list[j];
                        j--;
                        if (j < 0)
                        {
                            done = true;
                        }
                    }
                    else
                    {
                        done = true;
                    }
                } while (!done);
                list[j + 1] = val;
            }
            return list;
        }

 

首先是從前日後進行循環,將數據與前一個比較並交換位置。

看一下性能:

 

第八種:奇偶排序

經過比較相鄰的奇偶數進行排序,對存在錯誤的順序進行交換。並一直重複這個過程,直到列表有序。

public static IList<int> OddEventSort(IList<int> list)
        {
            bool sorted = false;
            while (!sorted)
            {
                sorted = true;
                for (int i = 1; i < list.Count - 1; i += 2)
                {
                    if (((IComparable)list[i]).CompareTo(list[i + 1]) > 0)
                    {
                        list[i] = list[i + 1] + (list[i + 1] = list[i]) * 0;
                        sorted = false;
                    }
                }
                for (int i = 0; i < list.Count - 1; i += 2)
                {
                    if (((IComparable)list[i]).CompareTo(list[i + 1]) > 0)
                    {
                        list[i] = list[i + 1] + (list[i + 1] = list[i]) * 0;
                        sorted = false;
                    }
                }
            }
            return list;
        }

 

看一下性能

 

第九種:鴿巢排序(大數據量中最快的排序方法)

鴿巢排序假設有個待排序的數組,給它創建一個空的輔助數組(俗稱鴿巢)。把原始數組的每一個值做爲格子(鴿巢的索引),遍歷原始數據,根據每一個值放入輔助數組對應的格子中。

順序遍歷鴿巢數組,把非空的鴿巢中的元素放回原始數組。這種排序方式適合在差值很小的範圍內使用。

public static IList<int> PigeonHoleSort(IList<int> list)
        {
            int min = list[0], max = list[0];
            foreach (int x in list)
            {
                if (((IComparable)min).CompareTo(x) > 0)
                {
                    min = x;
                }
                if (((IComparable)max).CompareTo(x) < 0)
                {
                    max = x;
                }
            }
            int size = max - min + 1;
            int[] holes = new int[size];
            foreach (int x in list)
            {
                holes[x - min]++;
            }
            int i = 0;
            for (int count = 0; count < size; count++)
            {
                while (holes[count]-- > 0)
                {
                    list[i] = count + (int)min;
                    i++;
                }
            }
            return list;
        }

 

看一下性能

 

第十種:快速排序(小數據量中最快方法)

快速排序會把集合分爲兩個集合,並選擇一個元素做爲基準。把小於基準的數據排到基準前面,大於放到後面。

public static IList<int> QuickSort(IList<int> list, int left, int right)
        {
            right = right == 0 ? list.Count - 1 : right;
            int i = left, j = right;
            double privotValue = (left + right) / 2;
            int x = list[(int)privotValue];
            while (i <= j)
            {
                while (((IComparable)list[i]).CompareTo(x) < 0)
                {
                    i++;
                }
                while (((IComparable)x).CompareTo(list[j]) < 0)
                {
                    j--;
                }
                if (i <= j)
                {
                    list[i] = list[j] + (list[j] = list[i]) * 0;
                    i++;
                    j--;
                }
            }
            if (left < j)
            {
                QuickSort(list, left, j);
            }
            if (i < right)
            {
                QuickSort(list, i, right);
            }
            return list;
        }

 

看一下性能

 

第十一種:選擇排序

在未排序的列表中找到最小或最大的元素,存放到排序序列的起始位置,而後,再從剩餘的排序元素中繼續找尋最小(大)元素,放到末尾。

public static IList<int> SelectionSort(IList<int> list)
        {
            int min;
            for (int i = 0; i < list.Count; i++)
            {
                min = i;
                for (int j = i + 1; j < list.Count; j++)
                {
                    if (((IComparable)list[j]).CompareTo(list[min]) < 0)
                    {
                        min = j;
                    }
                }
                list[i] = list[min] + (list[min] = list[i]) * 0;
            }
            return list;
        }

 

看一下性能

 

第十二種:希爾排序

經過將比較的所有元素分爲幾個區域來提高插入排序的性能。這樣可讓一個元素一次性地朝最終位置前進一大步。而後步伐愈來愈小,最後就是普通的插入排序。

 int length = list.Length;
            for (int h = length / 2; h > 0; h = h / 2)
            {
                for (int i = h; i < length; i++)
                {
                    int temp = list[i];
                    if (temp.CompareTo(list[i - h]) < 0)
                    {
                        for (int j = 0; j < i; j += h)
                        {
                            if (temp.CompareTo(list[j]) < 0)
                            {
                                temp = list[j];
                                list[j] = list[i];
                                list[i] = temp;
                            }
                        }
                    }
                }
            }
            return list;

 

 

看一下性能

相關文章
相關標籤/搜索