【问题描述】将n个无大小顺序的数,按照大小排序。
【算法思想】将待排序元素分成大致相同的两组,分别对两个子集合进行排序,最终将排好序的子集合合并成所要求的排好序的集合。
1、序列的合并
首先看,两个已序的序列的合并。举例,下面两个已序的序列:
先将两个已序的序列合并到另外一个序列里面
假设上述的序列都是在队列的结构中的话,要完成的过程就是先比较队列A和B队头的元素,如果A队头的元素比较小,那么就将A中队头元素取出,放入队列C中,这就完成了一次元素的转存;随后继续比较队列A和队列B队头的元素,将较小的元素存入序列C中,这样整个过程完成的时候C中就是一个排好序的元素序列了。
上述过程中,如果一共有N个元素,那么就进行了N次元素的比较操作。
将上述过程描述成程序如下:
//将序列1 src[0 ... mid] 和序列2 src[mid+1 ... right]
//两个序列归并到dst
template <class Type>
void Merge(Type src[], Type dst[], int left, int mid, int right)
{
int l = left; //指向序列1
int r = mid + 1; //指向序列2
int dt = left; //指向目的序列
while(l <= mid && r <= right) //如果两个序列都没有到头
{
if(src[l] < src[r]) //如果序列1中的值较小,将序列1中的值写到目标序列中
dst[dt++] = src[l++]; //序列1索引往后移动,目标序列索引往后移动
else //如果序列2中的值较小,将序列2中的值写到目标序列中
dst[dt++] = src[r++]; //序列2索引往后移动,目标序列索引往后移动
}
if(l > mid) //如果序列2还没有读完
{
for(int i=r; i<=right; ++i)
dst[dt++] = src[i]; //依次读入剩下的序列
}
else //如果序列1还没有读完
{
for(int i=l; i<=mid; ++i) //依次读入剩下的序列
dst[dt++] = src[i];
}
}
2、递归实现归并排序
对于一个随机的未排序的序列来说。如果序列长度是1,显然就不需要排序。否则,可以递归地将前半部分和后半部分序列进行归并排序(不仅仅是合并!)
程序描述如下:
template <class Type>
void MergeSort(Type a[],int left,int right)
{
if (left < right) //序列中不止有一个元素
{
int i = (left + right) / 2;
MergeSort(a,left,i); //对左侧归并排序
MergeSort(a,i+1,right); //对右侧归并排序
Merge(a,b,left,i,right); //合并左右序列
for(int k=left; k<=right; k++)
{
a[k] = b[k];
}
}
}
3、举例
#include <iostream>
using namespace std;
int a[11] = {9,8,4,65,21,31,6,17,101,11,52};
int b[11];
//完成序列的合并
//原序列src[left ... middle] src[middle+1 ... middle]合并到dst[]中
template <class Type>
void Merge(Type src[],Type dst[],int left,int middle,int right)
{
int l = left; //指向序列src[left ... middle]待取出的首元素位置
int r = middle+1; //指向序列src[middle+1 ... right]待取出的首元素位置
int dt = left; //指向目标序列dst待存入的首元素位置
//若src[left ... middle] 和 src[middle+1 ... right]中元素均未取完
while ((l <= middle) && (r <= right))
{
if (src[l] < src[r])
dst[dt++] = src[l++];
else
dst[dt++] = src[r++];
}
if (l > middle)//src[left ... middle]序列内容取完了,将剩余src[middle+1 ... right]依次填入
{
for (int i = r;i <= right;i++)
{
dst[dt++] = src[i];
}
}
else //src[middle+1 ... right]序列内容取完了,将剩余src[left ... middle]依次填入
{
for (int i = l;i <= middle;i++)
{
dst[dt++] = src[i];
}
}
}
template <class Type>
void MergeSort(Type a[],int left,int right)
{
if (left < right)
{
int i = (left + right) / 2;
MergeSort(a, left, i);
MergeSort(a, i+1, right);
Merge(a, b, left, i, right);
for(int k = left; k <= right; k++)
{
a[k] = b[k];
}
}
}
int main()
{
for(int i=0; i<11; i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
MergeSort(a,0,10);
for(int i=0; i<11; i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
system("pause");
return 0;
}