【分治法】合并排序及C++源码

来源:互联网 发布:linux守护进程编写 编辑:程序博客网 时间:2024/05/22 04:40

(1)合并排序是成功应用分治技术的一个完美例子。

对于一个需要排列的数组A[0..n-1],合并排序将它一分为二:A[0..[n/2]-1]和A[[n/2]..n-1],并对每个子数组递归排序,然后把这个排好序的子数组合并为一个有序数组。

Mergesort(A[0..n-1])// 递归调用 mergesort来对数组A[0..n-1]排序// 输入:一个可排序数组A[0..n-1]// 输出:非降序排列的数组A[0..n-1]if n>1   copy A[0..[n/2]-1] to B[0..[n/2]-1]   copy A[[n/2]..n-1] to C[0..[n/2]-1]    Mergesort(B[0..[n/2]-1])    Mergesort(C[0..[n/2]-1])    Merge(B,C,A)

(2)对两个有序数组的合并采用以下算法:

①初始状态下,两个指针(数组下标)分别指向两个待合并数组的第一个元素。

②然后比较这两个数组的大小,将较小的元素添加到一个新创建的数组中。

③接着,被复制的数组中的指针后移,指向该较小元素的后继元素。

(上述操作一直持续到两个数组中的一个被处理完为止。然后在未处理完的数组中,剩下的元素被复制到新数组的尾部)

Merge(B[0..p-1],C[0..q-1],A[0..p+q-1])// 将两个有序数组合并为一个有序数组// 输入:两个有序数组B[0..p-1]和C[0..q-1]// 输出:A[0..p+q-1]中已经有序存放了B和C中的元素i<-0;j<-0;k<-0while i<p and j<q do  if B[i]<=C[j]      A[k]<-B[i];i<-i+1  else A[k]<-C[j];j<-j+1  k<-k+1if i=p     copy C[j..q-1]to A[k..p+q-1]else copy B[i..p-1]to A[k..p+q-1]

(3)下图演示的是用合并排序算法对数列54,24,50,46,84,49,20,60进行排序的操作过程。

这里写图片描述

(4)合并算法效率

合并排序在最坏情况下的键值比较次数十分接近于任何基于比较的排序算法在理论上能够达到的最少次数。合并排序的主要缺点就是该算法需要线性的额外空间。虽然合并也能做到“在位”,但会导致算法过于复杂。而且,因为它的增长次数具有一个很大的常系数,所以在位的合并排序算法只具有理论上的意义。

当n>1时,C(n)=2C(n/2)+Cmerge(n),

C(1)=0,

对于最坏情况Cmerge(n)=n-1

当n>1时,Cworst(n)=nlog②n-n+1

(5)C++源码实现

#include <iostream>using namespace std;void Merge(int a[],int b[],int l,int m,int r){ int i=l,j=m+1,k=l;    while ((i<=m)&&(j<=r))  if (a[i]<=a[j])b[k++]=a[i++];  else b[k++]=a[j++];  if (i>m)for (int q=j;q<=r;q++)   b[k++]=a[q];  else for (int q=i;q<=m;q++)b[k++]=a[q];}void Copy(int a[],int b[],int s,int n){ for(int i=s;i<=n;i++)  a[i]=b[i];}void MergeSort(int a[],int left,int right){   int i; if(left<right) {i=(left+right)/2; int b[100]; MergeSort(a,left,i); MergeSort(a,i+1,right);    Merge(a,b,left,i,right); Copy(a,b,left,right);}}int main(){   int t;cin>>t;while (t--){int a[100]; int n,i; cin>>n; for ( i=0;i<n;i++)  cin>>a[i]; MergeSort(a,0,n-1);   for ( i=0;i<n;i++)  cout<<a[i]<<' ';   cout<<endl;}   return 0;}
原创粉丝点击