歸併排序(MERGE_SORT)
1)分治思想 :歸併排序用到了一種稱爲分治法的設計方法,分治法的思想就是將原問題的分解成爲幾個規模小的但是類似於原問題的子問題,遞歸的求解子問題,之後再合併子問題的解,來組成原問題的解。
2)原理 :根據分治方法的思想,歸併排序算法的基本操作分爲三大步:分解,解決問題,合併結果。以一個需要排序的數組爲例,分解也就是不停地遞歸分解問題,直到問題的規模降爲1,然後開始合併。
3)C語言實現 :
void merge(int from, int mid, int to, int* a)
{
//新建了一個輔助的數組,用來暫時寄存merge時的數組
int left_top, right_top, index, count, *t;
index = 0;
//左半邊的等待merge數組的頂端
left_top = from;
//右半邊的等待merge數組的頂端
right_top = mid + 1;
//整個merge後的數組長度
count = to - from;
t = (int*)malloc( (count + 1) * 2);
//不斷的從左右兩個需要merge的子數組中取出頂端較小的數字
//直到其中一個數組取盡
while ((left_top <= mid) && (right_top <= to))
{
if (a[left_top] < a[right_top])
{
t[index++] = a[left_top++];
}
else
{
t[index++] = a[right_top++];
}
}
//下面兩個while循環
//作用是將還沒有取盡的數組元素放入merge時的暫存數組中
while (left_top <= mid)
{
t[index++] = a[left_top++];
}
while (right_top <= to)
{
t[index++] = a[right_top++];
}
//將merge暫存數組的結果給原數組
for (int i = 0; i <= count; i++)
{
a[from++] = t[i];
}
}
void merge_sort(int from, int to, int* a)
{
if (from < to)
{
//分解問題
int mid = (from + to) / 2;
merge_sort(from, mid, a);
merge_sort(mid + 1, to, a);
//開始合併
merge(from, mid, to, a);
}
}
void main()
{
int count, *p;
printf("please input the count :");
scanf_s("%d", &count);
p = (int *)malloc(count * 2);
printf("\nplease input the number to be sorted : \n");
for (int i = 0; i < count; i++)
{
scanf_s("%d", p+i);
}
merge_sort(0, count-1, p);
for (int i = 0; i < count; i++)
{
printf("%d ", p[i]);
}
system("pause");
}
3)分析:上面實現的MERGE_SORT算法在輸入的數字數量爲奇數和偶數的時候都可以正常的工作,但是這裏我們爲了方便分析效率,將問題的規模假設爲2的冪,在每次分解問題的時候都可以分成n/2。我們按照三個步驟來分析效率:
- 分解:分解步驟只需要找到數組的中間位置,因此時間是常數O(1)。
- 解決:分解之後,需要遞歸的求解兩個規模爲n/2的子問題,花費時間爲2T(n/2)。
- 合併:將兩個長度爲n/2是的數組合併成一個長度爲n的數組,相當於將n個元素都遍歷了一遍,時間複雜度爲O(n)。
因此我們可以寫出T(n)和T(n/2)的關係表達式,T(n) = 2T(n/2) + cn(c爲常數);後面會分析可以從這個式子導出T(n) = O(nlgn)。