对于排序大列表数据,一个有效的排序算法是归并排序。类似于快速排序算法,其使用的是分治法来排序。归并排序的基本思想是:将两个或两个以上的有序子序列”归并”为一个有序序列。在内部排序中,通常采用的是2-路归并排序。即:将两个位置相邻的有序子序列“归并”为一个有序序列。
算法描述
归并操作的工作原理如下: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 设定两个指针,最初位置分别为两个已经排序序列的起始位置 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 重复步骤3直到某一指针达到序列尾 将另一序列剩下的所有元素直接复制到合并序列尾
一、基本思想
二路归并排序的基本思想是:将有n个记录的原始序列看作n个有序子序列,每个子序的长度为1,然后从第一个子序列开始,把相邻的子序列两两合关,得到n/2个长度为2或1的子序列(当子序列的个数为奇数时,最后一组合并得到的序列长度为1),我们把这一过程称为一次归并排序,对一次归并排序的n/2个子序列采用上述方法继续顺序成对归并,如此重复,当最后得到长度为n的一个子序列时,该子序列便是原始序列归并排序后的有序序列。
第一步,将列表中的11个元素看成11个有序的序列,每个子序列的长度为1,然后两两归并,得到5个长度为2和1个长度为1的有序子序列。
第二步,将6个有序子序列两两归并,得到2个长度为4和1个长度为3的有序子序列。
第三步,将2个长度为4的有序子序列归并,得到第三趟归并结果。
第四步,将长度为8有序子序列和长度为3的有序子序列归并,得到第四趟归并结果,是长度为11的一个有序子序列。
二、并归排序的实现

public
void
MergeSort(SeqList
<
int
>
sqList)
{
int k = 1 ; // 归并增量
while (k < sqList.GetLength())
{
Merge(sqList, k);
k *= 2 ;
}
}
public void Merge(SeqList < int > sqList, int len)
{
int m = 0 ; // 临时顺序表的起始位置
int l1 = 0 ; // 第1个有序表的起始位置
int h1; // 第1个有序表的结束位置
int l2; // 第2个有序表的起始位置
int h2; // 第2个有序表的结束位置
int i = 0 ;
int j = 0 ;
// 临时表,用于临时将两个有序表合并为一个有序表
SeqList < int > tmp = new SeqList < int > (sqList.GetLength());
// 归并处理
while (l1 + len < sqList.GetLength())
{
l2 = l1 + len; // 第2个有序表的起始位置
h1 = l2 - 1 ; // 第1个有序表的结束位置
// 第2个有序表的结束位置
h2 = (l2 + len - 1 < sqList.GetLength()) ? l2 + len - 1 : sqList.Length - 1 ;
j = l2;
i = l1;
// 两个有序表中的记录没有排序完
while ((i <= h1) && (j <= h2))
{
// 第1个有序表记录的关键码小于第2个有序表记录的关键码
if (sqList.Data[i] <= sqList.Data[j])
{
tmp.Data[m ++ ] = sqList.Data[i ++ ];
}
// 第2个有序表记录的关键码小于第1个有序表记录的关键码
else
{
tmp.Data[m ++ ] = sqList.Data[j ++ ];
}
}
// 第1个有序表中还有记录没有排序完
while (i <= h1)
{
tmp.Data[m ++ ] = sqList.Data[i ++ ];
}
// 第2个有序表中还有记录没有排序完
while (j <= h2)
{
tmp.Data[m ++ ] = sqList.Data[j ++ ];
}
l1 = h2 + 1 ;
}
i = l1;
// 原顺序表中还有记录没有排序完
while (i < sqList.GetLength())
{
tmp.Data[m ++ ] = sqList.Data[i ++ ];
}
// 临时顺序表中的记录复制到原顺序表,使原顺序表中的记录有序
for (i = 0 ; i < sqList.GetLength(); ++ i)
{
sqList.Data[i] = tmp.Data[i];
}
}
{
int k = 1 ; // 归并增量
while (k < sqList.GetLength())
{
Merge(sqList, k);
k *= 2 ;
}
}
public void Merge(SeqList < int > sqList, int len)
{
int m = 0 ; // 临时顺序表的起始位置
int l1 = 0 ; // 第1个有序表的起始位置
int h1; // 第1个有序表的结束位置
int l2; // 第2个有序表的起始位置
int h2; // 第2个有序表的结束位置
int i = 0 ;
int j = 0 ;
// 临时表,用于临时将两个有序表合并为一个有序表
SeqList < int > tmp = new SeqList < int > (sqList.GetLength());
// 归并处理
while (l1 + len < sqList.GetLength())
{
l2 = l1 + len; // 第2个有序表的起始位置
h1 = l2 - 1 ; // 第1个有序表的结束位置
// 第2个有序表的结束位置
h2 = (l2 + len - 1 < sqList.GetLength()) ? l2 + len - 1 : sqList.Length - 1 ;
j = l2;
i = l1;
// 两个有序表中的记录没有排序完
while ((i <= h1) && (j <= h2))
{
// 第1个有序表记录的关键码小于第2个有序表记录的关键码
if (sqList.Data[i] <= sqList.Data[j])
{
tmp.Data[m ++ ] = sqList.Data[i ++ ];
}
// 第2个有序表记录的关键码小于第1个有序表记录的关键码
else
{
tmp.Data[m ++ ] = sqList.Data[j ++ ];
}
}
// 第1个有序表中还有记录没有排序完
while (i <= h1)
{
tmp.Data[m ++ ] = sqList.Data[i ++ ];
}
// 第2个有序表中还有记录没有排序完
while (j <= h2)
{
tmp.Data[m ++ ] = sqList.Data[j ++ ];
}
l1 = h2 + 1 ;
}
i = l1;
// 原顺序表中还有记录没有排序完
while (i < sqList.GetLength())
{
tmp.Data[m ++ ] = sqList.Data[i ++ ];
}
// 临时顺序表中的记录复制到原顺序表,使原顺序表中的记录有序
for (i = 0 ; i < sqList.GetLength(); ++ i)
{
sqList.Data[i] = tmp.Data[i];
}
}
三、时间复杂度分析
二路归并排序的时间复杂度为O(nlog2n)。二路归并排序算法的空间复杂度为O(n)。