两路归并排序(Merge Sort),也就是我们常说的归并排序,也叫合并排序。它是建立在归并操作上的一种有效的排序算法,归并操作即将两个已经排序的序列合并成一个序列的操作。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
归并操作的基本步骤如下:
1.申请两个与已经排序序列相同大小的空间,并将两个序列拷贝其中;
2.设定最初位置分别为两个已经拷贝排序序列的起始位置,比较两个序列元素的大小,依次选择相对小的元素放到原始序列;
3.重复2直到某一拷贝序列全部放入原始序列,将另一个序列剩下的所有元素直接复制到原始序列尾。
设归并排序的当前区间是R[low..high],分治法的三个步骤是:
1.分解:将当前区间一分为二,即求分裂点
2.求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序;
3.组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]。
递归的终结条件:子区间长度为1(一个记录自然有序)。
举例
无序数组[6 2 4 1 5 9]
先看一下每个步骤下的状态,完了再看合并细节
第一步 [6 2 4 1 5 9]原始状态
第二步 [2 6] [1 4] [5 9]两两合并排序,排序细节后边介绍
第三步 [1 2 4 6] [5 9]继续两组两组合并
第四步 [1 2 4 5 6 9]合并完毕,排序完毕
输出结果[1 2 4 5 6 9]
合并细节
详细介绍第二步到第三步的过程,其余类似
第二步:[2 6] [1 4] [5 9]
两两合并,其实仅合并[2 6] [1 4],所以[5 9]不管它,
原始状态
第一个数组[2 6]
第二个数组[1 4]
--------------------
第三个数组[...]
第1步,顺序从第一,第二个数组里取出一个数字:2和1
比较大小后将小的放入第三个数组,此时变成下边这样
第一个数组[2 6]
第二个数组[4]
--------------------
第三个数组[1]
第2步,继续刚才的步骤,顺序从第一,第二个数组里取数据,2和4,
同样的比较大小后将小的放入第三个数组,此时状态如下
第一个数组[6]
第二个数组[4]
--------------------
第三个数组[1 2]
第3步,再重复前边的步骤变成,将较小的4放入第三个数组后变成如下状态
第一个数组[6]
第二个数组[...]
--------------------
第三个数组[1 2 4]
第4步,最后将6放入,排序完毕
第一个数组[...]
第二个数组[...]
--------------------
第三个数组[1 2 4 6]
[ 1 2 4 6 ]与[ 5 9 ]的合并过程与上边一样,不再分解。
例题:
ARR[]= {32, 21, 67};
示意图如下:
代码:
// merge_sort.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
int d[100] = {0};
//int s[10] = {32, 21, 67, 11, 5, 43, 99, 18, 22, 87};
int s[10] = {32, 21, 67};
void merg(int L, int R)
{
int mid = (L + R)/2;
int i = L, j = mid + 1, k = 0; //i表示前个区的第一个地址,j表示后一个区的第一个地址,k表示新地址
while (i <= mid && j <= R)
{
if(s[i] < s[j])
{
d[k++]=s[i++];
}
else
{
d[k++]=s[j++];
}
}
while(i<=mid)d[k++]=s[i++];
while(j<=R)d[k++]=s[j++];
for(i=L,k=0;i<=R;i++,k++)
s[i]=d[k];
}
void mergesort(int L,int R)
{
if (L < R)
{
int mid = (L + R)/2;
mergesort(L, mid);
mergesort(mid + 1, R);
merg(L, R);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
mergesort(0,2);
for(int i = 0; i < 10; i++)
{
cout << s[i] << endl;
}
return 0;
}