C++實現歸併排序(使用迴圈實現)
阿新 • • 發佈:2019-02-05
在上一篇文章中實現了遞迴方法的歸併排序。歸併排序時間效率很好,雖然使用遞迴的方法實現很簡單易讀,但是容易造成空間效能上的損耗(反覆的函式呼叫引起)。因此,有采用迴圈的方式實現歸排序。給出了兩種寫法,一種是我自己寫的(第一種),一種是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;
}
結果如圖