1.快速排序
(此处步骤是一个大佬的)
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j–由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
————————————————
原文链接:https://blog.youkuaiyun.com/code_AC/article/details/74158681
#include<iostream>
using namespace std;
const int N=1e6+10;
int n;
int a[N];
void qs(int a[],int l,int r) //
{
if(l>=r) return;
int x=a[l],i=l-1,j=r+1; //i,j需要各自先往两边偏移1
while(i<j)
{
do(i++) ;while(a[i]<x);
do(j--) ;while(a[j]>x);
if(i<j) swap(a[i],a[j]); //
}
qs(a,l,j);
qs(a,j+1,r);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
qs(a,0,n-1);
for(int i=0;i<n;i++) printf("%d",a[i]);
return 0;
}
例题:ACWing 1591. 快速排序
在著名的快速排序中,有一个经典的过程叫做划分。
在此过程中,我们通常选取其中一个元素作为分界值。
将小于分界值的元素移到其左侧,将大于分界值的元素移到其右侧。
给定 NN 个不同的正整数进行过一次划分后的排列情况。
请你判断,共有多少元素可能是此次划分的分界值。
例如,N=5N=5,各元素排列为 1,3,2,4,51,3,2,4,5,则:
- 11 可能是分界值,因为它的左侧没有元素,而右侧的元素都比它大。
- 33 一定不是分界值,因为尽管它的左侧的元素都比它小,但是它右侧的 22 也小于它。
- 22 一定不是分界值,因为尽管它的右侧的元素都比它大,但是它左侧的 33 也大于它。
- 出于类似判断可知 4,54,5 也可能是分界值。
因此,在此样例中,共有 33 个可能的分界值。
输入格式
第一行包含整数 NN。
第二行包含 NN 个不同的正整数。
输出格式
第一行输出可能的分界值数量。
第二行按升序顺序输出所有可能的分界值。
如果分界值数量为 00,则在输出分界值数量后,输出一个空行即可。
数据范围
1≤N≤10^5,
1≤1≤ 给定元素 ≤10^9。
输入样例:
5
1 3 2 4 5
输出样例:
3
1 4 5
难度:简单 |
时/空限制:0.2s / 64MB |
总通过数:537 |
总尝试数:2090 |
来源:PAT甲级真题1101 |
算法标签 |
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+20;
const int INF = 1e9+10;
int a[N], leftMax[N], rightMin[N];
int b[N], s;//记录主元 num是主元个数
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
leftMax[0] = 0;
for (int i = 1; i < n; i ++ ) leftMax[i] = max(leftMax[i - 1], a[i - 1]);
rightMin[n - 1] = INF;
for(int i = n - 2; i >= 0; i -- ) rightMin [i] = min(rightMin[i + 1], a[i + 1]);
for(int i = 0; i < n; i ++ )
{
if(leftMax[i] < a[i] && rightMin[i] > a[i])
b[s++] = a[i];//记录主元
}
printf("%d\n", s);
for(int i = 0; i < s; i ++ )
{
printf("%d", b[i]);
if(i < s - 1) printf(" ");
}
printf("\n");
return 0;
}
2.归并排序
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],tmp[N];
void ms(int a[],int l,int r)
{
if(l>=r) return;
int x=(l+r)/2;
ms(a,l,x);
ms(a,x+1,r);
int k=0,i=l,j=x+1;
while(i<=x&&j<=r)
{
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=x) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(int k=l,q=0;k<=r;k++,q++)
a[k]=tmp[q];
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
ms(a,0,n-1);
for(int i=0;i<n;i++) printf("%d ",a[i]);
return 0;
}
例题:ACWing 逆序对的数量
给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。
输入格式
第一行包含整数n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1 <= n <= 100000
输入样例:
6
2 3 4 5 6 1
1
2
输出样例:
5
1
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],tmp[N];
int s=0;
int ms(int a[],int l,int r)
{
if(l>=r) return 0;
int x=(l+r)/2;
ms(a,l,x);
ms(a,x+1,r);
int i=l,j=x+1,k=0;
while(i<=x&&j<=r)
{
if(a[i]<a[j]) tmp[k++]=a[i++];
else{
tmp[k++]=a[j++];
s=s+x-i+1; //
}
}
while(i<=x) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(int k=l,q=0;k<=r;k++,q++)
a[k]=tmp[q];
return s;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
cout<<ms(a,0,n-1);
//for(int i=0;i<n;i++) printf("%d ",a[i]);
return 0;
}