歸併排序是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。
歸併操作:
歸併操作(merge),也叫歸併算法,指的是將兩個順序序列合併成一個順序序列的方法。
如 設有數列{6,202,100,301,38,8,1}
初始狀態:6,202,100,301,38,8,1
第一次歸併後:{6,202},{100,301},{8,38},{1},比較次數:3;
第二次歸併後:{6,100,202,301},{1,8,38},比較次數:4;
第三次歸併後:{1,6,8,38,100,202,301},比較次數:4;
總的比較次數爲:3+4+4=11,;
逆序數爲14;
算法描述:
歸併操作的工作原理如下:
第一步:申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
第二步:設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
重複步驟3直到某一指針超出序列尾
將另一序列剩下的所有元素直接複製到合併序列尾
這裏寫代碼片
#include<stdio.h>
#include<stdlib.h>
void array_show(int* arr, int len);
void mergeSort(int a[], int n);
int main(int argc, char* argv[])
{
int arr[10] = {4,3,8,5,2,1,6,0,7,9};
array_show(arr, 10);
mergeSort(arr, 10);
putchar(10);
array_show(arr, 10);
system("pause");
return 0;
}
void array_show(int* arr, int len)
{
int i ;
for(i = 0; i != len; i ++)
{
printf("%d ", arr[i]);
}
}
void mergeTwoArray(int a[], int lena, int b[], int lenb)
{
int* tmparray=new int[lena+lenb];
int i=0, j=0, k=0;
while(i<lena && j<lenb)
{
if(a[i]<b[j])
{
tmparray[k]=a[i];
i++,k++;
}
else
{
tmparray[k]=b[j];
j++,k++;
}
}
while(i<lena)
{
tmparray[k]=a[i];
i++,k++;
}
while(j<lenb)
{
tmparray[k]=b[j];
j++,k++;
}
for(i=0; i<lena+lenb; i++)
{
a[i]=tmparray[i];
}
delete [] tmparray;
}
void mergeSort(int a[], int n)
{
if(n>1)
{
int mid=n/2;
int lena=mid;
int lenb=n-mid;
int* b=a+mid;
mergeSort(a,lena);
mergeSort(b,lenb);
mergeTwoArray(a,lena,b,lenb);
}
}
歸併排序是穩定的排序,即相等的元素的順序不會改變,速度僅次於快速排序。
時間複雜度爲O(nlogn) 這是該算法中最好、最壞和平均的時間性能。
空間複雜度爲 O(n),比較操作的次數介於(nlogn) / 2和nlogn - n + 1。
賦值操作的次數是(2nlogn)。
歸併算法的空間複雜度爲:0 (n)
歸併排序比較佔用內存,但卻是一種效率高且穩定的算法。