归并排序也是一种分治思想的典型应用,把两个或两个以上的有序表合并成一个有序表,即把待排序序列分成若干子序列,每个子序列是有序的,之后再把有序子序列合并成整体有序序列。
归并排序的平均时间复杂度为O(nlogn),最坏情况为O(nlogn),最优情况为O(n),空间复杂度为O(n),因为排序过程中要用到暂存区,所以该算法比较耗内存,但是效率比较高且是稳定排序。
归并排序的递归版本如下:
void Merge(int a[], int first, int mid, int last, int temp[]){
int i, j, k;
i = first;
j = mid + 1;
k = first;
while(i <= mid && j <= last){
if(a[i] < a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while(i <= mid)
temp[k++] = a[i++];
while(j <= last)
temp[k++] = a[j++];
i = k = first;
while(i <= last && k <= last){ // 把排好序的暂存区回写到原序列中
a[i++] = temp[k++];
}
}
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);
Merge(a,first, mid, last, temp);
}
}
归并排序非递归版本如下:
void mergesortNonRecursion(int a[], int n, int temp[]){
int size = 1, low, mid, high;
while(size <= n-1){ // 递归版其实是把序列每次1/2的往下分解,非递归就是这个过程逆过来,用两个循环,外循环加倍步长size,内循环用size分割子序列,分段合并子序列
low = 0;
while(low + size <= n-1){
mid = low + size-1;
high = mid + size;
if(high > n - 1)
high = n - 1;
Merge(a, low, mid, high, temp);
printf("low:%d mid:%d high:%d ", low, mid, high);
low = high + 1;
}
size *= 2;
}
}
和快速排序算法一样,归并排序的非递归版本应该也能用栈来模拟实现,以后有时间再实现吧!