归并排序及对sort函数与stable_sort函数的分析

归并排序是一种稳定且高效的排序算法,在最好,最坏和平均情况下时间复杂度都是nlogn。该算法采用了分而治之的策略,将整个数组逐渐细分(二分的方法)直到每个小的数组只有一个元素,所以它一定是有序的,然后再逐层合并小数组得到有序的原数组。而每层合并的复杂度为O(n)。
本算法只有在合并时的代码多(也即是本算法的主要内容),但是合并两个有序数组并不难,我们可以再开一个临时的数组来辅助(这里是temp数组)。接下来看代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define maxn 500005
using namespace std;
int n;
int a[maxn],temp[maxn];
void merge(int a[],int l,int mid,int r){
 int i=l;
 int j=mid+1;
 int t=0;
 while(i<=mid&&j<=r){
  if(a[i]<=a[j])temp[t++]=a[i++];
  else temp[t++]=a[j++];
 }
 while(i<=mid){
  temp[t++]=a[i++];
 }
 while(j<=r){
  temp[t++]=a[j++];
 }
 for(int i=l;i<=r;i++)a[i]=temp[i-l];//最后将temp数组中的值再赋给a数组
}
void mergesort(int a[],int l,int r){
 if(l>=r)return;//l=r就表示只有一个元素了
 int mid=(l+r)>>1;
 mergesort(a,l,mid);
 mergesort(a,mid+1,r);
 merge(a,l,mid,r);
}
int main(){
 cin>>n;
 for(int i=1;i<=n;i++)cin>>a[i];
 mergesort(a,1,n);
 for(int i=1;i<=n;i++){
  if(i>1)cout<<" ";
  cout<<a[i];
 }
 return 0;
} 

另外归并排序的一个常用的地方是来求一组数中的逆序对数。因为归并排序左右两部分合并时,假设I在左边,j在右边,则左边比j大的元素个数=mid-i+1。这个可以很容易理解(左边最大的是mid,以及判断到了I,此时比j大的肯定是mid-i+1)所以求逆序对数时只需加一句。

while(i<=mid&&j<=r){
  if(a[i]<=a[j])temp[t++]=a[i++];
  else {
   temp[t++]=a[j++];
   ans+=mid-i+1;
  }
 }

大多数我们都可以使用STL中的sort函数来完成排序,复杂度为nlogn,实际上sort函数是一种改进的快速排序,是一种不稳定的排序。另外STL中还有一个stable_sort(稳定的排序)。stable_sort 和 sort的区别在于 前者作排序可以使原来的"相同"的值在序列中的相对位置不变
如 1 4 6 7 4’ (4 和 4’值相等,加上’ 表示是2个元素)
那么stable_sort能保证排序完 4 仍然在4’ 前 也就是输出1 4 4’ 6 7;但是sort 没有这个功能,算法不能保证这一点。
有的题出得很精妙,如果你用sort或stable_sort函数的话都会TIE。像洛谷的P1309,题目链接:https://www.luogu.com.cn/problem/P1309
我们通过分析题意可以这样想,我们为每轮比赛都另建两个数组win[]和lose[],我们可以知道win数组和lose数组内部一定是有序的。所以我们只需要每轮比赛完后合并这两个数组即可,时间复杂度为O(n)。这里用到的就是归并排序的核心思想。

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,r,q;
struct ti{
 int s,w,id;
 void operator =(ti x){
  s=x.s ;w=x.w ;id=x.id ;
 }
}sum[200010];
bool cmp(ti x,ti y){
 if(x.s !=y.s)return x.s >y.s ;
 return x.id <y.id ;
}
struct ti win[200010],lose[200010];
void merge(ti win[],ti lose[]){
 int i=1;
 int j=1;
 int t=1;
 while(i<=n&&j<=n){
  if(win[i].s>lose[j].s)sum[t++]=win[i++];
  else if(win[i].s==lose[j].s){
   if(win[i].id<lose[j].id) sum[t++]=win[i++];
   else sum[t++]=lose[j++];
  }
  else sum[t++]=lose[j++];
 }
 while(i<=n){
  sum[t++]=win[i++];
 }
 while(j<=n){
  sum[t++]=lose[j++];
 }
 
}
int main(){
 cin>>n>>r>>q;
 int N=2*n;
 for(int i=1;i<=N;i++){
  scanf("%d",&sum[i].s );
 }
 for(int i=1;i<=N;i++){
  scanf("%d",&sum[i].w );
  sum[i].id =i;
 }
 sort(sum+1,sum+N+1,cmp);//第一次排序可以使用sort来排。
 for(int i=1;i<=r;i++){
  int t1=1,t2=1;
  for(int j=1;j<N;j+=2){
   if(sum[j].w >sum[j+1].w ){
    sum[j].s ++;
    win[t1++]=sum[j];
    lose[t2++]=sum[j+1];
   }
   else {
   sum[j+1].s++;
   win[t1++]=sum[j+1];
   lose[t2++]=sum[j]; 
   }  
  }
  merge(win,lose);//每次比完后合并两数组即可
 } 
 cout<<sum[q].id <<endl;
 return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
sort和stable_sort都是排序算法。sort是基于快速排序实现的,而stable_sort是基于归并排序实现的。两者都可以对数据进行排序,但stable_sort是一种稳定排序,即排序后元素之间的相对位置不会改变,而sort是一种不稳定排序。在sort和stable_sort中,都可以自定义比较函数来指定排序的方式。在C++中使用这两个排序算法时,需要包含<algorithm>头文件。 在Python中,没有直接的stable_sort函数,但可以使用第三方库或自己实现稳定排序算法。python-stablesort是一个将Python 2.3中的稳定listsort算法移植到其他Python版本的项目。 归并排序可以在逻辑上看作是一个二叉树的操作,节点是数组区间,叶子节点的值就是数组元素。归并排序的过程类似二叉树的后序遍历。具体实现时,可以使用辅助数组来避免递归过程中频繁分配和释放内存的性能问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++中stable_sortsort学习及简单实现](https://blog.csdn.net/u012328476/article/details/124975509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [python-stablesort-开源](https://download.csdn.net/download/weixin_42128537/18018185)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值