歸併排序c++程式碼及詳細註釋
阿新 • • 發佈:2018-12-23
轉自: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; }