二分歸併排序是歸併排序(合併排序)裏面最簡單的一種實現。
這個算法的主要思想是:將被排序的數組劃分成相等的兩個子數組,然後遞歸使用同樣的算法分別對兩個子數組排序。最好將兩個排好序的子數組歸併成一個數組。
歸併的過程如下:假設兩個子數組是A和B,它們的元素都按照從小到大的順序排列。將A與B歸併後的數組記作C。設定兩個指針p1,p2,初始分別指向A和B的最小元素。歸併時只需比較p1,p2指向的元素,哪個元素小,就把它從原來的數組移到C,原來指向它的指針向後移動一個位置。如果A和B中有一個數組的元素已經被全部移走,那麼比較過程結束,剩下的工作就是將B中剩下的元素順序移動C的後面。
考慮10個數的數組:1,5,7,8,2,4,6,9,10,3,使用歸併排序算法,首先劃分成兩個子數組,即A=[1,5,7,8,2],B=[4,6,9,10,3]. 然後對於A和B分別調用同樣的算法進行排序。假設A和B已經完成排序,即A=[1,2,5,7,8],B=[3,4,6,9,10],下面進行歸併。首先1與3 比較,拿走1;接着2與3比較,拿走2;再接着5和3比較,拿走3,.........繼續下去,依次拿走4,5,6,7,8.這是A數組已經空了,比較結束,把B中剩下的9和10順序放到歸併後的數組中。
假設輸入規模爲n,最好情況下,需要比較n/2次,最壞情況下(n-1)次。時間複雜度就不推導了,爲nlogn。
下面給出合併兩個數組的代碼
//將有序數組a[]和b[]合併到c[]中
void merge(int a[], int n, int b[], int m, int c[])
{
int i, j, k;
i = j = k = 0;
while (i < n && j < m)
{
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}
while (i < n)
c[k++] = a[i++];
while (j < m)
c[k++] = b[j++];
}
可以將A,B組各自再分成二組。依次類推,當分出來的小組只有一個數據時,可以認爲這個小組組內已經達到了有序,然後再合併相鄰的二個小組就可以了。這樣通過先遞歸的分解數列,再合並數列就完成了歸併排序。代碼如下
void mergearray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m && j <= n)
{
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
mergesort(a, first, mid, temp); //左邊有序
mergesort(a, mid + 1, last, temp); //右邊有序
mergearray(a, first, mid, last, temp); //再將二個有序數列合併
}
}
bool MergeSort(int a[], int n)
{
int *p = new int[n];
if (p == NULL)
return false;
mergesort(a, 0, n - 1, p);
delete[] p;
return true;
}