您的位置:首页 > 其它

归并排序

2015-10-27 15:55 232 查看
归并排序:

该算法采用分治法,将已有序的子序列合并,得到完全有序的序列,即先使每个子序列有序。(可用来求逆序数)

方法:首先考虑如何将两个有序序列合并,这个只要比较两个子序列的当前元素谁打谁小,然后取小的那一个,并将那个子序列 i++ ,之后再进行比较,若其中一个数列进行到结束之后,将另一个数列中的数搬过来即可。

1,申请空间,使其大小大于等于两个有序序列的和,用来存放合并后的序列

2,设置两个变量(例 i , j )分别指向两有序序列的起始位置

3,比较两变量所指向的元素 a[ i ]和b[ j ],选择所需要的(看题意是要从大到小还是从小到大)元素(这里加入a[ i] < b [j ] ,从小到大排)a[ i ] 放入合并空间,并更新变量值(i ++)

4,重复3知道其中一个序列比较完,将另一序列剩下的元素搬过来即可

主函数中申请空间,最后释放空间

long long *p=(long long *)malloc(sizeof(long long )*n);
mergesort(a,0,n-1,p);
cout<<cnt<<endl;
free(p);
(这个就是求了逆序数,累加在cnt 上)

void Merge(long long *a,long long left,long long mid,long long right,long long *p)
{
long long n=mid,m=right;
long long i=left,j=mid+1;
long long k=0;
while(i<=n&&j<=m)
{
if(a[i]<=a[j])
p[k++]=a[i++];
else
{
p[k++]=a[j++];
cnt+=n-i+1;//因为a[i]到a[mid]位有序的,一旦a[i]>a[j]则从i到mid的所有数都大于a[j]因为题目从小到大排序所以这些数都需要交换到a[j]的后面
}
}
while(i<=n)
{
p[k++]=a[i++];
}
while(j<=m)
p[k++]=a[j++];
for(int i=0;i<k;++i)
a[left+i]=p[i];
}


上面是将两个有序序列合并,但如何让两个序列有序呢,这里的思路就是将数组分成两组A B ,如果这两组内的数据有序则可以进行合并了。之后再将A B 组分别各自再分成两组,依次类推,知道分出来的组里只有一个元素时可以认为已是有序的,然后再合并相邻的两个小组即可。如此要先通过递归分解数列再合并数列就完成了。

void mergesort(long long *a,long long left,long long right,long long *p)
{
if(left<right)
{
int mid=(left+right)/2;
mergesort(a,left,mid,p);
mergesort(a,mid+1,right,p);
Merge(a,left,mid,right,p);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: