目錄
一、概述
歸併排序圖示分析(百度百科找的一張圖)
思想:
歸併排序(Merging Sort)利用歸併思想實現的排序算法,原理是:
假定初始序列含有n個記錄,則可以看成是n個有序的子序列,每個子序列的長度爲1,然後兩兩合併,得到 n/2個長度爲2或1的有序子序列;然後再兩兩合併,……,如此重複,直至得到一個長度爲n的有序序列位置,這種排序算法稱爲二路歸併算法。
二、代碼分析
#include <iostream>
#include <vector>
#include <time.h> // 隨機數種子
#include <chrono> // 統計運行時間需要
using namespace std;
using namespace chrono;
#define RUN_SORT(FUNC) \
{ \
auto tStart = system_clock::now(); \
FUNC; \
auto tEnd = system_clock::now(); \
auto tCost = duration_cast<nanoseconds>(tEnd - tStart); \
cout << "耗時: " << tCost.count() << " ns(納秒).\n" << endl; \
}
template<typename T>
void Merge(vector<T>& vec, int beginPos, int midPos, int endPos)
{
int leftLen, rightLen, i, j, k;
leftLen = midPos - beginPos + 1;
rightLen = endPos - midPos;
T* leftArr = new T[leftLen];
T* rightArr = new T[rightLen];
// 數組分別保存左右兩邊數據
for (i = 0; i < leftLen; i++)
{
leftArr[i] = vec[beginPos + i];
}
for (j = 0; j < rightLen; j++)
{
rightArr[j] = vec[midPos + 1 + j];
}
i = j = 0;
k = beginPos;
// 接下來從左右兩數組比較合併
while (i < leftLen && j < rightLen)
{
if (leftArr[i] <= rightArr[j])
{
vec[k++] = leftArr[i++];
}
else
{
vec[k++] = rightArr[j++];
}
}
for (; i < leftLen; i++) // 如果左數組還有剩餘,則將剩餘元素合併到vec
{
vec[k++] = leftArr[i];
}
for (; j < rightLen; j++) // 如果右數組還有剩餘,則將剩餘元素合併到vec
{
vec[k++] = rightArr[j];
}
delete[] leftArr;
delete[] rightArr;
}
template<typename T>
void MergeSort(vector<T>& vec, int beginPos, int endPos)
{
int midPos;
if (beginPos < endPos)
{
midPos = (beginPos + endPos) / 2;
MergeSort(vec, beginPos, midPos); // 遞歸拆分左半邊數組
MergeSort(vec, midPos + 1, endPos); // 遞歸拆分右半邊數組
Merge(vec, beginPos, midPos, endPos); // 合併數組
}
}
template<typename T>
void printVec(const vector<T>& vec)
{
for (auto it : vec)
{
cout << it << " ";
}
cout << "\n\n";
}
int main()
{
srand((unsigned int)time(NULL));
int cnt = 1;
do
{
vector<int> vec;
for (size_t i = 0; i < 10; i++)
{
vec.push_back(rand() % 100);
}
cout << "************第[ "<<cnt<<" ]次歸併排序前序列:\n";
printVec(vec);
RUN_SORT(MergeSort(vec, 0, vec.size() - 1))
cout << "歸併排序後序列:\n";
printVec(vec);
} while (cnt++ < 5);
//system("pause"); // g++關閉,VS打開
return 0;
}
三、耗時分析
Linux和windows跑出效果:
可以看出,windows計時對於納秒級別不是很精準,Linux計時比較有參考性。
四、複雜度及穩定性分析
時間複雜度:O(nlogn).
空間複雜度:由於歸併過程中需要與原始記錄序列同樣數量的存儲空間存放歸併結果,以及遞歸時深度爲log2n的棧空間,因此空間複雜度爲O(n + logn)。
穩定性:歸併排序需要兩兩比較,不存在“跳躍”,是一種穩定的排序算法(關於排序算法穩定性,通俗的講就是能保證在排序前,兩個相等的數在序列中先後位置順序和排序後他們倆前後位置順序相同。)。