将两个按值有序序列合并成一个按值有序序列,则称之为二路归并排序,下面有自底向上和自顶向下的两种排序算法,自顶向下的排序在本文末讲述,使用递归实现,代码较简洁,经供参考。
1. 归并子算法:把位置相邻的两个按值有序序列合并成一个按值有序序列。例如把序列 X[s..u] = {3, 12, 23, 32}和 序列 X[u+1..v] = {2, 5, 8, 99} 合并成序列
Z[s..v] = {2, 3, 5, 8, 12, 23, 32, 99}, 注意合并前的元素都位于同一个有序序列的相邻位置,合并后的有序序列的下标与合并前的序列总的起始下标相同。
算法过程中需要三个整型变量,i 用来遍历归并的前一个有序序列,其初始位置是s;j 用来遍历归并的后一个有序序列,其初始值是u+1;q 用来指出归并后得到的有序序列的末尾元素的位置,其初始值是s。当遍历完成其中的一个有序序列之后,只需把另一个未结束有序序列的剩余元素复制到合并后的有序序列的末尾。
看代码:
//将有序的X[s..u]和X[u+1..v]归并为有序的Z[s..v] void merge(int X[], int Z[], int s, int u, int v) { int i, j, q; i = s; j = u + 1; q = s; while( i <= u && j<= v ) { if( X[i] <= X[j] ) Z[q++] = X[i++]; else Z[q++] = X[j++]; } while( i <= u ) //将X中剩余元素X[i..u]复制到Z Z[q++] = X[i++]; while( j <= v ) //将X中剩余元素X[j..v]复制到Z Z[q++] = X[j++]; }
2t 的,且各自按值有序的子序列。
若某一趟归并扫描到最后,剩下的元素个数不足两个子序列的长度时:
/* X[0..n-1]表示参加排序的初始序列 * t为某一趟归并时子序列的长度 * 整型变量i指出当前归并的两个子序列中第1个子序列的第1个元素的位置 * Y[0..n-1]表示这一趟归并后的结果 */ void mergePass(int X[], int Y[], int n, int t) { int i = 0, j; while( n - i >= 2 * t ) //将相邻的两个长度为t的各自有序的子序列合并成一个长度为2t的子序列 { merge(X, Y, i, i + t - 1, i + 2 * t - 1); i = i + 2 * t; } if( n - i > t ) //若最后剩下的元素个数大于一个子序列的长度t时 merge(X, Y, i, i + t - 1, n - 1); else //n-i <= t时,相当于只是把X[i..n-1]序列中的数据赋值给Y[i..n-1] for( j = i ; j < n ; ++j ) Y[j] = X[j]; }
void mergeSort(int X[], int n) { int t = 1; int *Y = (int *)malloc(sizeof(int) * n); while( t < n ) { mergePass(X, Y, n, t); t *= 2; mergePass(Y, X, n, t); t *= 2; } free(Y); }
#include <stdlib.h> #include <stdio.h> //将有序的X[s..u]和X[u+1..v]归并为有序的Z[s..v] void merge(int X[], int Z[], int s, int u, int v) { int i, j, q; i = s; j = u + 1; q = s; while( i <= u && j<= v ) { if( X[i] <= X[j] ) Z[q++] = X[i++]; else Z[q++] = X[j++]; } while( i <= u ) //将X中剩余元素X[i..u]复制到Z Z[q++] = X[i++]; while( j <= v ) //将X中剩余元素X[j..v]复制到Z Z[q++] = X[j++]; } /* X[0..n-1]表示参加排序的初始序列 * t为某一趟归并时子序列的长度 * 整型变量i指出当前归并的两个子序列中第1个子序列的第1个元素的位置 * Y[0..n-1]表示这一趟归并后的结果 */ void mergePass(int X[], int Y[], int n, int t) { int i = 0, j; while( n - i >= 2 * t ) //将相邻的两个长度为t的各自有序的子序列合并成一个长度为2t的子序列 { merge(X, Y, i, i + t - 1, i + 2 * t - 1); i = i + 2 * t; } if( n - i > t ) //若最后剩下的元素个数大于一个子序列的长度t时 merge(X, Y, i, i + t - 1, n - 1); else //n-i <= t时,相当于只是把X[i..n-1]序列中的数据赋值给Y[i..n-1] for( j = i ; j < n ; ++j ) Y[j] = X[j]; } void mergeSort(int X[], int n) { int t = 1; int *Y = (int *)malloc(sizeof(int) * n); while( t < n ) { mergePass(X, Y, n, t); t *= 2; mergePass(Y, X, n, t); t *= 2; } free(Y); } void print_array(int array[], int n) { int i; for( i = 0 ; i < n ; ++i ) printf("%d ", array[i]); printf("\n"); } int main() { int array[] = {65, 2, 6, 1, 90, 78, 105, 67, 35, 23, 3, 88, -22}; int size = sizeof(array) / sizeof(int); mergeSort(array, size); print_array(array, size); return 0; }
void merge2(int *data, int start, int mid, int end) { int *temp = (int *)malloc((end-start+1)*sizeof(int)); int i = start; int j = mid + 1; int k = 0; while(i <= mid && j <= end) { temp[k++] = data[i] <= data[j] ? data[i++] : data[j++]; } while(i <= mid) temp[k++] = data[i++]; while(j <= end) temp[k++] = data[j++]; k = 0; for(i = start; i <= end; ++i) data[i] = temp[k++]; free(temp); } //从顶往下 void mergeSort2(int *data, int start, int end, int *des) { if(start == end) return; int mid = (end + start)/2; mergeSort2(data, start, mid, des); mergeSort2(data, mid+1, end, des); merge2(data, start, mid, end); }