归并-逆序数、快排-第k小数

目录

 

归并排序:

完整代码:

快速排序:


归并排序:

思路:进行二分,然后合并。对于合并的两个模块,每一个模块必定已排好,因为是排完才合并。

例如2 4 6 | 1 3 7;双“指针”,一个指向左边、一个指向右边。

  1. 右边1<左边2  1进入b数组 此时2 4 6|3 7  b={1};
  2. 右边3>左边2  2进入b数组 此时4 6|3 7    b={1,2}

……

以此类推。

由此发现,右边的进入时,左边剩下了多少就有多少逆序对,并且合并回溯过程中,每一个数都会和它前面的数进行分组(就是这里的左右)。

所以,只需在需要将右边数加入时加上这条语句即可ans += (ll)(mid-p1+1);mid时最后一个左组元素的下标。

注意:等号的时候让左组进入,因为相等这不是逆序对。

void _merge(int l,int mid,int r){
	int p1 = l,p2 = mid+1;
	for(int i = l;i <= r;i++){
		if(((a[p1] <= a[p2])||(p2 > r))&&p1<=mid){
			b[i] = a[p1++];
		}//等号无所谓,这里为了求逆对数,相等的情况让前面的先进去,主要靠后面进行求逆对数 
		else {
			b[i] = a[p2++];
		}
	}
	for(int i = l;i <= r;i++)	a[i] = b[i];
	return ;
}
void erfen(int l,int r){
	int mid = (l+r)>>1;
	if(l < r){
		erfen(l,mid);
		erfen(mid+1,r);
	}
	_merge(l,mid,r);
	return ;
} 

完整代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<map>
#include<cmath>
#include<vector>

using namespace std;
typedef long long ll;
const int maxn = 1e6+50;
ll a[maxn];
ll b[maxn];
ll ans;
void _merge(int l,int mid,int r){
	int p1 = l,p2 = mid+1;
	for(int i = l;i <= r;i++){
		if(((a[p1] <= a[p2])||(p2 > r))&&p1<=mid){
			b[i] = a[p1++];
		}//等号无所谓,这里为了求逆对数,相等的情况让前面的先进去,主要靠后面进行求逆对数 
		else {
			b[i] = a[p2++];
			ans += (ll)(mid-p1+1);
		}
	}
	for(int i = l;i <= r;i++)	a[i] = b[i];
	return ;
}
void erfen(int l,int r){
	int mid = (l+r)>>1;
	if(l < r){
		erfen(l,mid);
		erfen(mid+1,r);
	}
	_merge(l,mid,r);
	return ;
} 
int main(){
	int n;
	cin >> n;
	for(int i = 0;i < n;i++)	cin >> a[i];
	ans = 0;
	erfen(0,n-1); 
	cout << ans << endl;
	return 0;
}

快速排序:

找到一个基准点,小于它的在左侧,大于它的在右侧,然后递归对两侧同样执行。

void q_sort(int l,int r){
         int i = l,j = r;
         int mid = (l+r)>>1;
         int x = a[mid]; 
         while(i <= j){ 
                  while(a[i] < x) i++; 
                  while(a[j] > x)  j--;
                   if(i <= j){
                            swap(a[i],a[j]);
                            i++;j--;
                   }
         } 
        if(l < j) 
            q_sort(l,j);
         if(i < r) 
            q_sort(i,r);
}    

寻找第k小数,那么就进行改进。

如果找到了一个数,基准点位置最后在….x…..,如果x<k的话,左侧肯定不会是第k小数,都没有k个数,左侧不必再排序,砍掉一半。如果x>k的话,右侧肯定不会是第k小数,因为左侧多余k个数,右侧都大于左侧,所以肯定在左侧。

void q_sort(int l,int r){
         int i = l,j = r;
         int mid = (l+r)>>1;
         int x = a[mid];
         while(i <= j){
                   while(a[i] < x) i++;
                   while(a[j] > x)  j--;
                   if(i <= j){
                            swap(a[i],a[j]);
                            i++;j--;
                   }
         }
         if(k == i-1){
                   printf("%d\n",a[k]);
                   return ;
         } 
         else if(k < i-1){
                   q_sort(l,i-1);
         }        
         else q_sort(i,r);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值