C++實現歸併排序Mergesort(使用遞迴的方法)
阿新 • • 發佈:2019-01-06
歸併排序的最壞執行時間為
假設N是2的冪次,從而每次總能分裂成兩個相等的子列。對於
其中,對於N個數的歸併排序用的時間等於兩個大小為
把上面的式子兩邊同時除以N,得到以下的遞推關係:
然後把上面的式子相加,消去等號兩邊相等的項,該過程稱之為疊縮求和,最後得到的結果為
因為總的方程個數等於執行歸併排序中子列長度變化的次數
所以得到:
得證。
下面給出使用遞迴方法的程式:
#include<iostream>
#include<vector>
#include<random>
#include<ctime>
#include<iterator>
#include<algorithm>
using namespace std;
/*
使用遞迴的歸併排序
該函式為驅動函式
*/
template<typename Comparable>
void mergeSortRecursive(vector<Comparable> &a)
{
vector<Comparable> tmpArray(a.size());
mergeSortRecursive(a, tmpArray, 0, a.size() - 1);
}
/*
實現採用遞迴的歸併排序
a為原始資料
tmpArray用於存放歸併排序過程中的結果
left表示迭代中子列的最左端的下標
right表示迭代中子列的最右端的下標
*/
template<typename Comparable>
void mergeSortRecursive(vector<Comparable> &a,
vector<Comparable> &tmpArray, int left, int right)
{
if (left < right)
{
int center = (right + left) / 2;
mergeSortRecursive(a, tmpArray, left, center);
mergeSortRecursive(a, tmpArray, center + 1, right);
merge(a, tmpArray, left, center + 1, right);
}
}
/*
歸併排序中使用的合併函式
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 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);
mergeSortRecursive(source);
cout << "排序後:" << endl;
printVector(source);
return 0;
}
該程式對merge每次都呼叫相同的臨時向量,因為每次呼叫merge的時候只有一個臨時向量在使用,因此建立和待排向量等長的臨時向量,每次使用的地方都是正在執行歸併排序操作下標起始處。
執行結果如下: