七大經典排序算法總結-C#

一.交換排序

   1.冒泡排序

     基本思路:1.對相鄰的兩個進行比較,如果前者比後者大,則進行交換,一輪比較後,找到最大值,而且最大值就會排在尾端

                        2.對出去最大值意外的剩餘部分,重複1操作,直到找完,即完成排序

      1)經典冒泡

        private static void BubbleSortFun(List<int> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                for (int j = 0; j <list.Count -i-1; j++)
                {
                    if (list[j ] > list[j+1]) //如果第二個小於第一個數
                    {
                        //交換兩個數的位置
                        Swap(list, j , j+1);
                    }                
                }
            }

        }

    2)減少計算優化,減少了j判斷的計算

        private static void BubbleSortFun1(List<int> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                for (int j = list.Count-1; j >i; j--)
                {
                    if (list[j-1] > list[j]) //如果第二個小於第一個數
                    {
                        //交換兩個數的位置
                        Swap(list, j - 1, j);
                    }             
                }
            }

        }

    3)優化冒泡,設置標誌位,對已經排序好的,不再進行排序

        private static void BubbleSortFun2(List<int> list)
        {
            bool flg = true;   //設置排序標誌位
            for (int i = 0; i < list.Count && flg; i++)
            {
                flg = false;  //設置爲false ,如果無排序發生則證明已經排序好了
                for (int j = list.Count - 1; j > i; j--)
                {
                    if (list[j - 1] > list[j]) //如果第二個小於第一個數
                    {
                        //交換兩個數的位置
                        Swap(list,j-1,j);
                        flg = true;
                    }
                }
            }

        }

2.快速排序

基本思路:1.在已有序列中設置一個“基準”,一般設置第一個元素

                  2.進行分區,即將所有小於基準的數移動到基準的組邊,將所有大於基準的數放在基準的右邊

                  3.對左右分區分別重複1,2操作,直到無法分區爲止,即完成排序


        private static void QuickSortFun(List<int> list, int left, int right)
        {
            if (left < right)
            {
                int i = Division(list, left, right);
                //對樞軸的左邊部分進行排序
                QuickSortFun(list, i + 1, right);
                //對樞軸的右邊部分進行排序
                QuickSortFun(list, left, i - 1);
            }
        }  

        //獲取按樞軸值左右分流後樞軸的位置
        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; //指向的此時樞軸的位置
        }

二.插入排序

1.直接插入排序

     基本思路:1.從已有序列開始找到一個較小值,並用臨時變量保存它

                       2.將較小值前面比它大的數向後移動

                       3.當它前面無數字或比前面的數比它小,將它插入

                       4.以它後邊的數爲開始重複以上操作直到尾部,即完成排序

        private static void InsortSortFun(List<int> list)
        {
            int temp = 0;
            for (int i = 0; i < list.Count-1; i++)
            {
                if (list[i] <= list[i + 1])
                    continue;
                temp = list[i + 1];//temp保存要向前移動的數字,防止數字被覆蓋掉
                for (int j = i; j >= 0; j--)//numbers從第i個元素到第0個元素爲可能要向後移動的元素
                {
                    if (temp <= list[j])//numbers[j]需要向後移動一個位置
                        list[j + 1] = list[j];//numbers[j+1]已經移動過,或者保存在temp中了,所以不會丟失數據
                    else
                    {
                        list[j + 1] = temp;//j+1是要插入的位置
                        break;
                    }
                    if (j == 0)//值最小的情況
                        list[0] = temp;
                }
            }
        }

2.希爾排序

    基本思路:1.得到一個步長,一般進行二分

                      2.按步長進行分組,並組內數據進行比較,交換

                      3.縮小步長,重複1,2操作,直到步長爲0即完成排序

        private static  void ShellSortFun(List<int> list)
        {
            for (int step = list.Count / 2; step > 0; step /= 2)  //得到步長
            {
                for (int i = step; i < list.Count; i++)  //分組
                {
                    int j = 0;
                    int temp = list[i];
                    for (j = i - step; j >= 0 && temp < list[j]; j -= step) //對組內按步長比較後插入
                    {
                        list[j + step] = list[j];
                    }
                    list[j + step] = temp;
                }
            }
        }

三.選擇排序

     1.簡單選擇排序

            基本思路:1.在已有的序列中,設置一個臨時索引

                              2.在未排序的序列中找到最小值的索引,並用臨時索引記錄

                              3.如果臨時索引值不等於未排序序列的最小索引,則進行交換

                              4.對未排序的序列重複以上操作,直到序列尾部,即完成排序

              

        private static void SelectSortFun(List<int> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                int key = i; //保存key

                for (int j = i + 1; j < list.Count; j++)//
                {
                    if (list[j] < list[key]) key = j;
                }

                if (key != i)
                {
                    int temp = list[i];
                    list[i] = list[key];
                    list[key] = temp;
                }
            }
        }

2.堆排序

    基本思路:1.對未排序的序列,以二叉樹的方式創建堆

                      2.對堆內數據進行比較,將最大值置於堆頂

                      3.將交換第一個元素和最後一個元素(因爲第一個元素即爲堆頂)

                      4.堆的大小減1,重複1,2,3操作,直到堆大小減少到0爲止,即完成排序

       private static void HeapSortFun(List<int> list)
        {
            int count = list.Count;
            CreatHeap(list, count);

            for (int i = count - 1; i >= 0; i--)  //交換第一個元素和最後一個元素後,堆的大小減1
            {
                //最後一個元素和第一個元素進行交換
                Swap(list, 0, i);

                CreatHeap(list, i);
            }

        }

        private static void CreatHeap(List<int> list,int count)
        {
            int parent=count / 2 - 1;
            for (int i =parent; i >=0; i--)
            {
                int left = i * 2 + 1; //左子樹節點
                 int right = i * 2 + 2; //右子樹節點
                //選出左右子節點中最大的
                int max = 0;
                if (right < count)
                {
                    max = list[left] > list[right] ? left : right;
                }
                else
                    max = left;

                if (list[max] > list[i])   //交換子節點與父節點
                {
                    Swap(list, max, i);
                }
            }
        }
        /// <summary>
        /// 交換
        /// </summary>
        /// <param name="numbers"></param>
        /// <param name="i"></param>
        /// <param name="j"></param>
        private static void Swap(List<int> numbers, int i, int j)
        {
            int number = numbers[i]; //把大的數放在一個臨時存儲位置
            numbers[i] = numbers[j]; //然後把小的數賦給前一個,保證每趟排序前面的最小
            numbers[j] = number; //然後把臨時位置的那個大數賦給後一個
        }

四.歸併排序

        基本思路:1.對已有序列進行拆分,直到拆分到足夠小,一半左右都是1

                           2.設置一個臨時序列,大小等於拆分好的序列大小

                           3.將拆分好的序列內進行比較,並存入臨時序列,臨時序列即爲有序

                           4.將臨時序列合併到原序列即完成排序

       private static void MergeSortFun(int[] array, int first, int last)
        {
            if (first < last)
            {
                //表拆分
                int mid = (first + last) / 2;
                MergeSortFun(array, first, mid); //左側子表
                MergeSortFun(array, mid + 1, last); //右側子表

                //比較合併
                MergeSortCore(array, first, mid, last);
            }
        }

        /// <summary>
        /// 子表比較,合併
        /// </summary>
        /// <param name="array"></param>
        /// <param name="first"></param>
        /// <param name="mid"></param>
        /// <param name="last"></param>
        private static void MergeSortCore(int[] array, int first, int mid, int last)
        {
            int leftIndex = first;
            int rightIndex = mid + 1;

            int[] temp = new int[last - first + 1];
            int tempIndex = 0;

            //把較小的數值放入臨時數組,有一側子表遍歷完後,跳出循環
            while (leftIndex <= mid && rightIndex <= last)
            {
                if (array[leftIndex] <= array[rightIndex])
                {
                    temp[tempIndex++] = array[leftIndex++];
                }
                else
                {
                    temp[tempIndex++] = array[rightIndex++];
                }
            }

            //將另外一側子表剩下的數一次放入暫存數組中(有序)
            while (leftIndex <= mid)
            {
                temp[tempIndex++] = array[leftIndex++];
            }

            while (rightIndex <= last)
            {
                temp[tempIndex++] = array[rightIndex++];
            }

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

        }

以上完整代碼:https://download.csdn.net/download/shu19880720/11001823

總結

     排序算法的穩定性是指排序前後具有相同關鍵字的記錄,相對順序保持不變。形式化的定義就是,排序之前有ri=rj,ri在rj之前,而在排序之後ri仍然在rj之前,就說這種算法是穩定的。各排序算法的比較如下所示:

參考:https://www.cnblogs.com/lz3018/p/5742255.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章