1. 程式人生 > >C++實現歸併排序(使用迴圈實現)

C++實現歸併排序(使用迴圈實現)

上一篇文章中實現了遞迴方法的歸併排序。歸併排序時間效率很好,雖然使用遞迴的方法實現很簡單易讀,但是容易造成空間效能上的損耗(反覆的函式呼叫引起)。因此,有采用迴圈的方式實現歸排序。給出了兩種寫法,一種是我自己寫的(第一種),一種是weiss書上的課後習題的參考答案(第二種),思想是一樣的,第二種明顯比第一種寫法簡單很多。

程式如下


#include<iostream>
#include<vector>
#include<random>
#include<ctime>
#include<iterator>
#include<algorithm>
using namespace std; /* 歸併排序中使用的合併函式 a為原始資料 tmpArray用於存放歸併排序過程中的結果 leftPos表示前一個子列的最左端的元素的下標 rightPos表示後一個子列的最左端的元素的下標 rightEnd表示後一個子列的最右端的元素的下標 */ template<typename Comparable> void merge(vector<Comparable> &a, vector<Comparable> &tmpArray, int leftPos, int rightPos, int
rightEnd) { int leftEnd = rightPos - 1; int tmpPos = leftPos; // 用來儲存在合併過程中存放結果的臨時向量的下標 int numElements = rightEnd - leftPos + 1; //主迴圈,把資料合併 while (leftPos <= leftEnd && rightPos <= rightEnd) { if (a[leftPos] < a[rightPos]) tmpArray[tmpPos++] = a[leftPos++]; else
tmpArray[tmpPos++] = a[rightPos++]; } //如果是因為後邊子列的資料全部放在臨時向量中導致主迴圈結束 //則把前面沒放完的資料依次放入臨時變數中 while (leftPos <= leftEnd) tmpArray[tmpPos++] = a[leftPos++]; //同上處理前面子列資料全部先放入向量中的情況 while (rightPos <= rightEnd) tmpArray[tmpPos++] = a[rightPos++]; //注意!不能直接用a=tmpArray,因為可能只是複製子列 for (int i = 0; i < numElements; ++i, --rightEnd) a[rightEnd] = tmpArray[rightEnd]; } /* 使用迴圈的歸併排序 */ template<typename Comparable> void mergeSortLoop(vector<Comparable> &a) { // 迴圈實現的第一種編寫方法 vector<Comparable> tmpArray(a.size()); // 定義一個臨時向量 int numElements = a.size();//待排元素的總個數 // 注意,第一個元素的下標為0,最後一個元素的下標為n-1 for (size_t k = 1; k < a.size(); k *= 2) { int leftStart = 0;//初始化左邊那個子列的開始下標 int gap = 2 * k;//兩個子列的長度(每次歸併時的長度) //通過迴圈不斷的把完整的兩個子列歸併 while ((leftStart + gap) < numElements) { merge(a, tmpArray, leftStart, leftStart + k, leftStart + gap - 1); leftStart += gap; } //對於向量中最後幾個元素 //如果剩下的元素長度大於一個子列的長度,則需要歸併 //如果剩下的元素長度小於等於一個子列的長度,不需要歸併,此時該子列已經有序 if ((numElements - leftStart) > k) { merge(a, tmpArray, leftStart, leftStart + k, numElements-1); } //注意,每次在執行merge的時候,就把排好的子列從tmpArray中複製到了a中 } /* //迴圈實現的第二種編寫方法 int n = a.size(); vector<Comparable> tmpArray(n); for (int subListSize = 1; subListSize < n; subListSize *= 2) { int part1Start = 0; while (part1Start + subListSize < n ) { int part2Start = part1Start + subListSize; int part2End = min(n-1, part2Start + subListSize - 1); merge(a, tmpArray, part1Start, part2Start, part2End); part1Start = part2End + 1; } } */ } /*輸出向量*/ template<typename T> void printVector(vector<T> & v) { copy(v.cbegin(), v.cend(), ostream_iterator<T>(cout, " ")); cout << endl; } int main() { vector<int> source; uniform_int_distribution<int> u(0, 1000); default_random_engine e(static_cast<unsigned int>(time(0))); for (int i = 0; i < 31; i++) { source.push_back(u(e)); } cout << "排序前:" << endl; printVector(source); mergeSortLoop(source); cout << "排序後:" << endl; printVector(source); return 0; }

結果如圖
這裡寫圖片描述