資料結構排序之合併排序
阿新 • • 發佈:2018-12-11
合併排序是用分治策略的一個排序演算法。
其基本思想是將待排序元素分成大小大致相同的兩個子序列,對兩個子序列進行排序後,再進行合併。
通俗來講,待排序元素不停的分解與合併,這是一個重複且相似的過程。
假設有n個元素,我們將其劃分兩半,再對其中的一部分再劃分兩半,重複此操作,直至最小序列長度為2或3的時候,我們對最小序列進行分解按大小合併,我們就得到一個排序成功的最小子序列,再將其與同級的最小子序列(已經做了同樣操作排過序)進行按大小合併。重複此操作,直到 n/2長度的序列與n/2長度的序列合併,合併排序算完成。
merge函式 用來合併p-q 與 q-r 兩個長度序列(按照遞增序列)
void merge(int num[],int p,int q,int r) { int n1 = q - p + 1; //前半段的長度 int n2 = r - q + 1; //後半段的長度 int left[n1+1], right[n2]; for(int i = 0; i < n1;++i) left[i] = num[p + i]; //將前半段複製到左邊 left[n1] = 65536; //最後一位設定為大值防止排序時出錯 for(int j = 0; j < n2; ++j) right[j] = num[q + j + 1]; //將後半段複製到右邊 right[n2-1] = 65536; int i = 0,j = 0; for(int x = p ; x <= r; x++ ) //將左右合併 { if (left[i] < right[j]) { num[x] = left[i++]; } else { num[x] = right[j++]; } } }
mergeSort函式 劃分區域
void mergeSort(int num[],int p,int r)
{
if(p < r) //當p=r的時候說明只有1個元素,最低也要有2個元素
{
int q = (p + r) / 2; //劃分位置
mergeSort(num, p, q); //將左邊進行歸併排序
mergeSort(num, q+1, r); //將右邊進行歸併排序
merge(num, p, q, r); //將左右合併
}
}
時間複雜度:
因為每次會分成大致均等的兩部分,所以對於n個元素,它大概會合並O(log₂n)次,而每個量級區域的合併總時間是O(n) (不管劃分多少區域,總數量還是n),所以合併排序的時間複雜度是O(n*log₂n)
#include <iostream>
#include <stdlib.h>
using namespace std;
void merge(int num[],int p,int q,int r)
{
int n1 = q - p + 1;
int n2 = r - q + 1;
int left[n1+1], right[n2];
for(int i = 0; i < n1;++i)
left[i] = num[p + i];
left[n1] = 65536;
for(int j = 0; j < n2; ++j)
right[j] = num[q + j + 1];
right[n2-1] = 65536;
int i = 0,j = 0;
for(int x = p ; x <= r; x++ )
{
if (left[i] < right[j])
{
num[x] = left[i++];
}
else
{
num[x] = right[j++];
}
}
}
void mergeSort(int num[],int p,int r)
{
if(p < r)
{
int q = (p + r) / 2;
mergeSort(num, p, q);
mergeSort(num, q+1, r);
merge(num, p, q, r);
}
}
int main()
{
int max;
cin >> max;
int num[max];
for(int i = 0; i < max; i++)
{
num[i] = rand() % 100;
}
mergeSort(num,0,max-1);
for(int i = 0;i < max; i++)
{
printf("%d ",num[i]);
}
return 0;
}