您的位置:首页 > 其它

排序算法(二)-- 归并排序

2014-10-04 07:58 183 查看

归并排序

归并排序算法使用分治策略

1. 分治法

将原问题划分成n个规模较小而结构与原问题相似的子问题;递归的解决这些子问题,然后再合并其结果,就得到原问题的解。

分治模式在每一层递归上有三个步骤:

分解: 将原来问题分解为一系列子问题
解决: 递归地解各子问题。若子问题足够小,则直接求解
合并: 将子问题合并成原问题的解。 

归并排序算法完全依照了上述模式,直观的操作如下:

分解: 将n个元素分成各含n/2个元素的子序列
解决: 用合并排序算法对两个子序列递归的排序
合并: 合并两个已排序的子序列以得到排序结果。
在对子序列排序时,其长度为一时递归结束。单个元素被认为是排好序的。

合并排序的关键步骤在于合并两个已排序的子序列,引入作为合并的辅助过程 Merge(A,p,q,r), 其中A为数组,p,q,r是下标,满足 p<=q<r, 该过程假设子数组A[p...q]和A[q+1...r]是已经排好序的, 将它们合并成一个已经排好序的子数组代替当前子数组A[p...r].

Merge过程的时间代价为O(n),n=r-p+1是待合并元素的个数。

算法的基本步骤如图:





算法实现的伪代码如图:



通过MergeSort对其排序



其算法实现:

void Merge(int A[], int p, int q, int r)
{
int n1 = q-p+1;		// 计算子数组A[p .. q]的长度
int n2 = r-q;		// 计算字数组A[q+1 .. r]的长度

int* L = new int[n1+1];     // 创建数组L(left)长度为(n1+1)
int* R = new int[n2+1];		// 创建数组R(right)长度为(n2+1)

// 将子数组A[p .. q]复制到L[1 .. n1]中去
for(int i = 0; i < n1; i++)
{
L[i] = A[p+i];
}
// 将子数组A[q+1 .. r]复制到 R[1 .. n2]中去
for(int j=0; j < n2; j++)
{
R[j] = A[q+j+1];
}

//将哨兵置于L和R的末尾
L[n1] = 1000;
R[n2] = 1000;

// 这里要注意,与原书不同,C++的程序数组从[0]开始
int i = 0;
int j = 0;

/* for循环每一轮迭代开始,子数组A[p .. k-1]包含了L[1..n1+1]和
R[1 .. n2+1]中的k-p个最小的元素。并且是排好序的。此外, L[i]和R[j]
是各自所在的数组中未被复制回数组A中的最小元素
*/
for(int k = p; k <= r; k++)
{
if(L[i] <= R[j])
{
A[k] = L[i];
i++;
}
else
{
A[k] = R[j];
j++;
}
}
}

// 对子数组A[p .. r]排序
/* 注: 排序中数组表示以C++为标准
调用函数:MergeSort(A ,0,n-1);
*/
void MergeSort(int A[], int p, int r)
{
/*
如果p>=r ,则该子数组中至多只有一个元素。则是已经排好序的
否则,分解步骤计算出一个下标q,将A[p .. r]分成A[p .. q]和
A[q+1 .. r].
*/
int q;
if(p <r)
{
q = (p+r)/2;
MergeSort(A,p,q);
MergeSort(A,q+1,r);
Merge(A,p,q,r);
}
}


(晕死,代码片不能保存,说含有敏感词汇,这里面那个词比较敏感啊?)

排序结果:



下图给出了n为2的幂时,自底向上的操作。



可以看出,递归排序比插入排序浪费空间。因为要申请一个和排序数组大小相同的数组空间,但是归并排序在性能上是优于插入排序的,它的时间复杂度远低于插入排序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: