1. 程式人生 > >歸併排序c++程式碼及詳細註釋

歸併排序c++程式碼及詳細註釋

轉自:http://www.cnblogs.com/hxf829/archive/2008/11/18/1659863.html

#include <iostream>
using namespace std;
template <class T>
void MSort(T a[], int left, int right)
{
      if (left < right)
      {
            int center = (left + right) / 2;//取得中點
            //將原來序列分為兩段
            MSort(a, left, center);
            MSort(a, center+1, right);
            //合併剛才分開的兩段,得到原來序列的有序序列
            Merge(a, left, center, right, right-left+1);
      }
}

template <class T>
void MergeSort(T a[], int n)
{
    //呼叫遞迴歸併排序函式
      MSort(a, 0, n-1);
}
template <class T>
void Merge(T a[], int left, int center, int right, int n)
{
      T *t = new T[n];//存放被排序的元素
      int i = left;
      int j = center + 1;
      int k = 0;
      //合併陣列,用插入排序,如果左邊大就插入左邊的數,右邊的計數器等待,與下一個左邊的數比較;右邊大就插入右邊的數,左邊的計數器等待,與下一個右邊的數比較(這裡指的插入是插入到新陣列t[])
      while (i<=center && j<=right)
      {
            if (a[i] <= a[j])
                  t[k++] = a[i++];
            else
                  t[k++] = a[j++];
      }
      //上面的步驟在執行完後,左或右邊都有可能剩餘若干個元素,而另一邊的元素肯定已全部複製到新陣列,這時需要特殊對待剩下的元素
      if (i == center+1)
      {
            while (j <= right)
                  t[k++] = a[j++];
      }
      else
      {
            while (i <= center)
                  t[k++] = a[i++];
      }
      //把t[]的元素複製回a[]中left到right段
      for (i=left,k=0; i<=right; i++,k++)
            a[i] = t[k];
      //釋放記憶體
      delete []t;
}
int main()
{
    int intArray[5] = { 5 , 6 , 2 , 5 , 9 };
    MergeSort(intArray,5);
    for(int i = 0; i < 5; i++)
        cout << intArray[i] << endl;
}
-------------------------------------------------------------------------------------
//非遞迴實現
#include <iostream>
using namespace std;

template <class T>
void MergeSort(T a[], int n)
{
    /*非遞迴形式:
演算法介紹:先介紹三個變數beforeLen,afterLen和i的作用:
int beforeLen; //合併前序列的長度
int afterLen;//合併後序列的長度,合併後序列的長度是合併前的兩倍
int i = 0;//開始合併時第一個序列的起始位置下標,每次都是從0開始
i,i+beforeLen-1,i+afterLen-1定義被合併的兩個序列的邊界。
演算法的工作過程如下:
開始時,beforeLen被置為1,i被置為0。外部for迴圈的迴圈體每執行一次,都使beforeLen和afterLen加倍。內部的while迴圈執行序列的合併工作,他的迴圈體每執行一次,i都向前移動afterLen個位置。當n不是afterLen的倍數時,如果被合併序列的起始位置i,加上合併後序列的長度afterLen,超過輸入陣列的邊界n,就結束內部迴圈;此時如果被合併序列的起始位置i,加上合併前序列的長度 beforeLen,小於輸入陣列的邊界n,還需要執行一次合併工作,把最後長度不足afterLen,但超過beforeLen的序列合併起來。這個工作由演算法的語句Merge(a, i, i+beforeLen-1, n-1, n);完成。*/
     /*  int beforeLen; //合併前序列的長度
      int afterLen = 1;//合併後序列的長度

     for (beforeLen=1; afterLen<n; beforeLen=afterLen)
      {
            int i = 0;//開始合併時第一個序列的起始位置下標,每次都是從0開始
            afterLen = 2 * beforeLen; //合併後序列的長度是合併前的兩倍

            while (i+afterLen < n)
            {
                  Merge(a, i, i+beforeLen-1, i+afterLen-1, afterLen);
                  i += afterLen;
            }

            if (i+beforeLen < n)
                  Merge(a, i, i+beforeLen-1, n-1, n);
      }*/
      //我自己寫的主函式程式碼
      int lengthTocombine = 1;//定義將要被合併的長度,開始時為1;
      int begin;
      for(lengthTocombine = 1;lengthTocombine < n; lengthTocombine *= 2)
      {
          begin = 0;//開始合併時第一個序列的起始位置下標,每次都是從0開始
          while(begin + 2*lengthTocombine < n )
          {
              Merge(a, begin, (2*begin+2*lengthTocombine-1)/2, begin+2*lengthTocombine-1, 2*lengthTocombine);
              begin += 2*lengthTocombine;
          }
          //剩下長度小於lengthTocombine序列
          if (begin + lengthTocombine < n)
              Merge(a, begin, begin+lengthTocombine-1, n-1, n);
      }
}
template <class T>
void Merge(T a[], int left, int center, int right, int n)
{
      T *t = new T[n];//存放被排序的元素
      int i = left;
      int j = center + 1;
      int k = 0;
      //合併陣列,用插入排序,如果左邊大就插入左邊的數,右邊的計數器等待,與下一個左邊的數比較;右邊大就插入右邊的數,左邊的計數器等待,與下一個右邊的數比較(這裡指的插入是插入到新陣列t[])
      while (i<=center && j<=right)
      {
            if (a[i] <= a[j])
                  t[k++] = a[i++];
            else
                  t[k++] = a[j++];
      }
      //上面的步驟在執行完後,左或右邊都有可能剩餘若干個元素,而另一邊的元素肯定已全部複製到新陣列,這時需要特殊對待剩下的元素
      if (i == center+1)
      {
            while (j <= right)
                  t[k++] = a[j++];
      }
      else
      {
            while (i <= center)
                  t[k++] = a[i++];
      }
      //把t[]的元素複製回a[]中left到right段
      for (i=left,k=0; i<=right; i++,k++)
            a[i] = t[k];
      //釋放記憶體
      delete []t;
}

int main()
{
    int intArray[5] = { 23 , 8 , 1 , 6 , 10};
    MergeSort(intArray,5);//執行排序
    for( int i = 0; i < 5; i++)
        cout << intArray[i] << endl;
}