歸併排序(merge Sort)

歸併排序有兩種方式:

(1): 自底向上的方法
自底向上的基本思想是:第1趟歸併排序時,將待排序的文件R[1..n]看作是n個長度爲1的有序子文件,將這些子文件兩兩歸併,若n爲偶數,則得到n/2個長度爲2的有序子文件;若n爲奇數,則最後一個子文件輪空(不參與歸併)。故本趟歸併完成後,前n/2 - 1個有序子文件長度爲2,但最後一個子文件長度仍爲1;第2趟歸併則是將第1趟歸併所得到的n/2個有序的子文件兩兩歸併,如此反覆,直到最後得到一個長度爲n的有序文件爲止。

初始化:{43,23,54,44,2,7,19}
第一趟:{23,43,44,54,2,7,19}
第二趟:{23,43,44,54,2,7,19}
第三趟:{2,7,19,23,43,44,54}
      第一趟   【43,23】【54,44】【2,7】【19】
      第二趟   【23,43,44,54】【2,7,19】 
      第三趟   【2,7,19,23,43,44,54】 
   // 歸併排序
        public void Merge(List<int> seqlist,int len)
        {
            int m = 0; //臨時順序表的起始位置
            int l1 = 0;//第1個有序表的起始位置
            int h1;    //第1個有序表的結束位置
            int l2;    //第2個有序表的起始位置
            int h2;    //第2個有序表的結束位置
            int i = 0; //臨時表示第一個有序表的起始位置
            int j = 0; //臨時表示第二個有序表的起始位置
            // 臨時表,用於臨時將2個有序表合併爲一個有序表
            List<int> tmp = new List<int>();
            for (int q = 0; q < seqlist.Count; q++)
            {
                tmp.Add(0);// 給list添加值
            }
            // 歸併處理
            while (l1+len<seqlist.Count)
            {
                l2 = l1 + len;//第二個有序表的開始位置
                h1 = l2 - 1;  //第一個有序表的結束位置
                // 第二個有序表的結束位置
                h2 = (l2 + len - 1 < seqlist.Count) ? l2 + len - 1 : seqlist.Count - 1;
                j = l2; //第二個有序表的起始位置賦給j
                i = l1; //第一個有序表的起始位置賦給i
                // 兩個有序表中的記錄沒有排序完
                while ((i<=h1)&&(j<=h2))
                {
                    //第一個有序表記錄的關鍵碼小於第二個有序表記錄的關鍵碼
                    if (seqlist[i]<=seqlist[j])
                    {
                        tmp[m++] = seqlist[i++];
                    }
                    else
                    {
                        tmp[m++] = seqlist[j++];

                    }
                }
                // 第一個有序表中還有記錄沒有排序完
                while (i<=h1)
                {
                    tmp[m++] = seqlist[i++];
                }
                // 第二個有序表中還有記錄沒有排序完
                while (j<=h2)
                {
                    tmp[m++] = seqlist[j++];
                }
                l1 = h2 + 1;
            }
            i = l1;
            // 原順序表中還有記錄沒有排序完
            while (i<seqlist.Count)
            {
                tmp[m++] = seqlist[i++];
            }
            // 臨時順序表中的記錄複製到順序表,使原順序表中的記錄有序
            for (i = 0; i < seqlist.Count; i++)
            {
                seqlist[i] = tmp[i];
            }
        }
    // 二路歸併排序算法
    public void MergeSort(List<int> seqlist)
      {
          int n = 1;// 歸併增量
          while (n < seqlist.Count)
          {
              Merge(seqlist,n);
              n *= 2;
          }
      }

對於n個記錄的順序表,將這n個記錄看作葉子結點,若將兩兩歸併生成的子
表看作它們的父結點,則歸併過程對應於由葉子結點向根結點生成一棵二叉樹的
過程。所以,歸併趟數約等於二叉樹的高度減1,即log2n,每趟歸併排序記錄關
鍵碼比較的次數都約爲n/2,記錄移動的次數爲2n(臨時順序表的記錄複製到原
順序表中記錄的移動次數爲n)。因此,二路歸併排序的時間複雜度爲O(nlog2n)。
而二路歸併排序使用了n個臨時內存單元存放記錄,所以,二路歸併排序算法的
空間複雜度爲O(n)。

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