一、如何合并两个有序数组?
归并排序算法的基本操作是合并两个已排序的表:对于两个已排好序的数组A和B、存放结果的数组C,设置三个计数器a、b和c,它们初始时置于数组的开始端,将A[a]和B[b]中的较小者存放在C[c]中,同时把相关的计数器向前推进一步。假设有已排序数组A={1,3,5,7}和已排序数组B={2,6,7,9,11,12},初始时,a=b=c=0。比较步骤如下:
首先1和2比较,1被加入到C中,a和c自增,a=1,b=0,c=1,C={1}
第2次比较在3和2之间进行,2被加入到C中,b和c自增,a=1,b=1,c=2,C={1,2}
第3次比较在3和6之间进行,3被加入到C中,a和c自增,a=2,b=1,c=3,C={1,2,3}
第4次比较在5和6之间进行,5被加入到C中,a和c自增,a=3,b=1,c=4,C={1,2,3,5}
第5次比较在7和6之间进行,6被加入到C中,b和c自增,a=3,b=2,c=5,C={1,2,3,5,6}
第6次比较在7和7之间进行,7被加入到C中,a(也可以是b)和c自增,a=4,b=2,c=5,C={1,2,3,5,6,7}
此时A中的所有元素都已经被加入到C中,现在只要将B中剩余的元素{7,9,11,12}复制到C的后面就完成了有序数组A和B的合并。最后C={1,2,3,5,6,7,7,9,11,12}。
完成两个有序数组(实际上是一个数组的两段,已排序的前半段和已排序的后半段)合并的函数merge的实现如下:
void merge(ElementType array[], ElementType tmpArray[],int lpos, int rpos,int rightend)
{
int leftend = rpos - 1;//前半段的最后位置
int NumElements = rightend - lpos + 1;//待排序元素的总数
int tmppos = lpos;
while (lpos <= leftend && rpos <= rightend)
if (array[lpos] <= array[rpos])
tmpArray[tmppos++] = array[lpos++];
else
tmpArray[tmppos++] = array[rpos++];
/*将剩余的部分加入到tmpArray中*/
while (lpos <= leftend)
tmpArray[tmppos++] = array[lpos++];
while (rpos <= rightend)
tmpArray[tmppos++] = array[rpos++];
/*将tmpArray中的结果复制回原数组array中*/
for (int i = 0; i < NumElements; i++, rightend--)
array[rightend] = tmpArray[rightend];
}
二、归并排序的思想
如果只有一个元素需要排序,那么答案是显然的。否则,将前半部分和后半部分各自归并排序,得到排序后的两部分在利用上面的方法进行合并就完成了所有元素的排序。而对于前半部分和后半部分的排序亦是如此。例如有待排序数组array={5,3,2,4,6,1,7},有n=5个元素,想将其分为两部分({5,3,2}{4,6,1,7}),这两个部分是无序的要再次进行归并排序,继续分割为(({5}{3,2})({4,6}{1,7}))。此时{5}只有一个元素,所以不用再进行分割,其他的还要分割,最后分割为({5} ({3}{2}) ) ( ({4}{6}) ({1}{7}) ),每一个圆括号表示一次归并。
第1次排序后:(({5} ({2,3}) ({4,6}{1,7} ))
第2次排序后:({2,3,5}{1,4,6,7} )
第3次排序后:{1,2,3,4,5,6,7}
归并排序的实现如下:
void MSort(ElementType array[], ElementType tmpArray[], int left, int right)
{
int center;
if (left < right)
{
center = (left + right) / 2;
MSort(array, tmpArray, left, center);
MSort(array, tmpArray, center + 1, right);
Merge(array, tmpArray, left, center + 1, right);
}
}
通常输入是一个数组array和待排序元素个数n,所以再给出归并排序的驱动函数如下:
void MergeSort(ElementType array[], int n)
{
ElementType *tmpArray;
tmpArray = (ElementType *)malloc(n * sizeof(ElementType));
if(tmpArray!=NULL)
MSort(array, tmpArray, 0, n - 1);
}