35. 排序演算法(8):歸併排序的迭代實現
阿新 • • 發佈:2019-02-13
1. 基本原理
在上篇文章中介紹了歸併排序的遞迴實現,雖然遞迴的實現方式很簡單,通過遞迴呼叫就可以實現,但是會佔用大量的時間和空間,使得演算法的效率下降;使用迭代的方式代替遞迴的方式雖然會使得程式碼的編寫變得困難,但是會增大效率。
遞迴的思想實際上是從上往下“遞”,再從下往上“歸”。遞迴的實現過程可以看成如下的過程
而迭代的過程就是化成一個個小的排序問題,再合併到一起,比如如下的過程
2. 程式碼實現
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
void MergeSort(int k[], int n)
{
// i 用於 for 迴圈迭代,temp 用來儲存臨時陣列,所以要給他分配記憶體
int i, next, left_min, left_max, right_min, right_max;
int *temp = (int *)malloc(n * sizeof(int));
// i 是步長,第一次是1個元素與1個元素相比,第2個是兩個元素與2個元素相比
for( i=1; i < n; i*=2 )
{
// left_min 最後是要小於 n-i 的,這一點可以通過畫圖得到
// left_min = right_max 是指上一組排序完成之後,將上一組的 right 賦值給下一組的 left_min
for( left_min=0; left_min < n-i; left_min = right_max )
{
right_min = left_max = left_min + i;
right_max = left_max + i;
// 因為奇數的陣列最後很有可能 right_max > n,所以將它限制到最大為 n
if( right_max > n )
{
right_max = n;
}
next = 0 ;
// 在這裡跟遞迴中的歸併操是一樣的,從兩個陣列中取小的出來放入臨時陣列
while( left_min < left_max && right_min < right_max )
{
if( k[left_min] < k[right_min] )
{
temp[next++] = k[left_min++];
}
else
{
temp[next++] = k[right_min++];
}
}
// 但是上面的過程並不會同時將左右兩個陣列的元素都放入臨時儲存陣列 temp 中
// 要麼左邊會剩一點,要麼右邊會剩一點,所以這個時候要對剩餘的進行操作
// 如果左邊剩了,說明這些應該是最大的,應該放在陣列的右邊
while( left_min < left_max )
{
k[--right_min] = k[--left_max];
}
// 將臨時儲存的元素放入陣列中得到最後的結果
while( next > 0 )
{
k[--right_min] = temp[--next];
}
}
}
}
int main()
{
int i, a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
MergeSort(a, 10);
printf("排序後的結果是:");
for( i=0; i < 10; i++ )
{
printf("%d", a[i]);
}
printf("\n\n");
return 0;
}