歸併排序 及 C++實現
歸併排序:
時間複雜度:O(nlogn)
優點:效率高、穩定
缺點:佔用記憶體較多
歸併排序是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併。
歸併過程為:比較a[i]和a[j]的大小,若a[i]≤a[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素a[j]複製到r[k]中,並令j和k分別加上1,如此迴圈下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的演算法我們通常用遞迴實現,先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。
以上內容來自百度百科。
歸併排序主要分為兩部分:
1、劃分子區間
2、合併子區間
現在以 9,6,7,22,20,33,16,20 為例講解上面兩個過程:
第一步,劃分子區間:每次遞迴的從中間把資料劃分為左區間和右區間。原始區間為[start,end],start=0,end=[length-1],減一是因為陣列的下標從0開始,本例中length=8,end=7.現在從中間元素劃分,劃分之後的左右區間分別為 [start,(end-start+1)/2+start],右區間為[(end-start+1)/2+start+1,end],本例中把start和end帶入可以得到[0,7],劃分後的左右子區間為[0,4],[5,7],然後分別對[start,end]=[0,4]和[start,end]=[5,7]重複上一步過程,直到每個子區間只有一個或者兩個元素。整個分解過程為:
子區間劃分好以後,分別對左右子區間進行排序,排好序之後,在遞迴的把左右子區間進行合併,整個過程如下圖所示:
程式碼如下:
歸併函式:
void merge_sort(vector<int> &data, int start, int end, vector<int> &result) { if (end - start == 1) { // 如果區間只有兩個元素,則對這兩個元素進行排序 if (data[start] > data[end]) { int temp = data[start]; data[start] = data[end]; data[end] = temp; } return; } else if (end - start == 0) // 如果區間只有一個元素,則不用排序 return; else { // 繼續劃分子區間,分別對左右子區間進行排序 merge_sort(data, start, (end-start+1)/2+start, result); merge_sort(data, (end-start+1)/2+start+1, end, result); // 開始歸併已經排好序的start到end之間的資料 merge(data, start, end, result); // 把排序後的區間資料複製到原始資料中去 for (int i = start; i <= end; i++) { data[i] = result[i]; } } } void merge(vector<int> &data, int start, int end, vector<int> &result) { int left_length = (end - start + 1) / 2 + 1; // 左部分割槽間的資料元素個數 int left_index = start; int right_index = start + left_length; int result_index = start; while ((left_index < start + left_length) && (right_index < end + 1)) { // 對分別已經排好序的左區間和右區間進行合併 if (data[left_index] <= data[right_index]) { result[result_index++] = data[left_index++]; } else result[result_index++] = data[right_index++]; } while (left_index < start + left_length) { result[result_index++] = data[left_index++]; } while (right_index < end + 1) { result[result_index++] = data[right_index++]; } }
測試主函式:
#include <iostream>
#include <vector>
using namespace std;
void merge_sort(vector<int> &data, int start, int end, vector<int> &result);
void merge(vector<int> &data, int start, int end, vector<int> &result);
int main() {
vector<int> data ={9, 6, 7, 22, 20, 33, 16, 20};
const int length = 8;
vector<int> result(length);
cout << "Before sorted: " << endl;
for (int i = 0; i < length; i++) {
cout << data[i] << " ";
}
cout << endl;
cout << "After sorted: " << endl;
merge_sort(data, 0, length-1, result);
for (int i = 0; i < length; i++) {
cout << data[i] << " ";
}
cout << endl;
return 0;
}