c++---归并排序笔记(求逆序数)

5 篇文章 0 订阅

 

 今天学习了一下关于排序的一点东西,发现是真多,下面说一下一个我觉得非常牛的排序,归并排序

网上很多都做过归并排序与sort()快速排序的排序时间的对比,结果归并排序比c++标准库定义的sort()还快

但它也不是没有缺点,就是空间的浪费的比较严重,它不是在原地址上进行修改,而是创建一个临时数组来

储存,再排序。下面我简单说一下我对它的理解:

感觉它有点像二分法的,就是先将数组分为两个部分,然后在将左右两部分在各分为两部分。。。。。。直到分为每一个

小组都是俩个元素,然后在对这两个元素排序(这里是要用那个创建的临时数组的),先将两个元素派完序后放入临时

数组中,然后在将临时数组放入要排序的数组,然后就是在将两两排序后的含有两个元素的子数组合并(这里合并的意思

也就是在把两个子数组当成两个元素,再进行排序,当然这里可以看出是递归的思想)。。。。。。然后到最后又将很多

的子数组有合并成一个大数组。

 

也就是

  一个数组  (要排序的数组)--------------分成很多只含两个元素的子数组--------------------------在合并成一个数组(已经排完序的)

 这里我觉的用递归的思想实现比较简单而且容易理解:

这里我觉得它就像是以前老师讲的递归的应用:

下面给出我的代码:

#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
//这是主要的功能函数,既包含了排序的功能,又包含了合并数组的功能
void mergearray(ll a[],ll first,ll mid,ll last,ll temp[])
{
    ll i = first,j=mid+1;
    ll m = mid,n=last,k=0;
    while(i<=m&&j<=n)
    {
        if(a[i] < a[j])
            temp[k++] = a[i++];
        else
            temp[k++] = a[j++];
    }
    while(i<=m)
        temp[k++] = a[i++];
    while(j<=m)
        temp[k++] = a[j++];
    for(ll i =0; i<k; i++)
    {
        a[i] = temp[i];
    }
}
//这个是对函数进行排序功能函数也就是分割数组
void mergesort(ll a[],ll first,ll last,ll temp[])
{
    if(first < last)//这里我觉得很重要,因为它将判断并将数组分为元素为两个的子数组
    {
        ll mid = (first+last)/2;
        mergesort(a,first,mid,temp);
        mergesort(a,mid+1,last,temp);
        mergearray(a,first,mid,last,temp);
    }

}
//下面的这个函数是像是一个用户的接口
void MergeSort(ll a[],ll n)
{
    ll *p = new ll[n];//创建一个临时数组,这里也可以不使用动态数组
    mergesort(a,0,n-1,p);//调用排序函数
    delete []p;
}
int main()
{
    ll a[5] = {5,6,4,2,8};
    MergeSort(a,5);
    for(ll i=0; i<5; i++)
    {
        cout << a[i] << " ";
    }
    return 0;
}
 

代码,中我觉得可能难理解的是关于递归的部分,前提你必须理解关于递归的思想(一条路走到尽头后,在走分路),

还有就是注意我这里是传入的数组的所以,所以在第一函数中遍历数组时要写等号,

一个数列有逆序数的性质,详情见线性代数。。。。

关于逆序数的应用有很多,这里只说我今天遇到的,就是求一个数列每次只能交换相邻的元素,最少经过多少次可以将其

变为有序的数列,注意这里只能交换相邻的元素而且是最少的次数,这里的最少次数就等于它的逆序数,其实这跟冒泡排序的的原理有点像,你可以自己退一下,上面的程序只要将mergearray()函数改一下就可以求一个数组的逆序数了,是不是觉得很神奇,也可能有的人会说没必要,但是在小中数据量上很快,下面给出我的代码:

 #include <iostream>
 #include <string>
 #include <algorithm>
 #include <map>
 #define ll long long
 using namespace std;
 ll cnt = 0;
 void mergearray(ll a[], ll first, ll mid, ll last, ll temp[])
 {
 ll i = first, j = mid + 1;
 ll m = mid, n = last;
 ll k = 0;
  
 while (i <= m && j <= n)
 {
 if (a[i] <= a[j])
 temp[k++] = a[i++];
 else
 {
 temp[k++] = a[j++];
 cnt += m-i+1;
 }
 }
 while (i <= m)
 temp[k++] = a[i++];
  
 while (j <= n)
 temp[k++] = a[j++];
  
 for (i = 0; i < k; i++)
 a[first + i] = temp[i];
 }
 void mergesort(ll a[], ll first, ll last, ll temp[])
 {
 if (first < last)
 {
 ll mid = (first + last) / 2;
 mergesort(a, first, mid, temp);
 mergesort(a, mid + 1, last, temp);
 mergearray(a, first, mid, last, temp);
 }
 }
  
 bool MergeSort(ll a[], ll n)
 {
 ll *p = new ll[n];
 if (p == NULL)
 return false;
 mergesort(a, 0, n - 1, p);
 delete[] p;
 return true;
 }
 int main()
 {
 ios::sync_with_stdio(false);
 cin.tie(0);cout.tie(0);
 ll n,m;
 cin >> n;
 for(ll i = 1; i <= n;i++)
 {
 cin >> m;
 cnt =0;
 ll* p = new ll[m];
 for(int i = 0;i<m;i++)
 {
 cin >> p[i];
 }
 MergeSort(p,m);
 delete []p;
 cout << "Scenario #"<<i<<":\n";
 cout << cnt<<"\n\n";
 }
 return 0;
  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值