排序
$$ \texttt{SeekLuna 2023.6.11} $$ 论 $\text{beyoursven}$ 有多恐怖这件事……
排序的一些性质
通过比较操作来给同类元素排序。
可排序性
要求比较规满足可排序性:
任意两个待排序的元素都可以进行比较
比较规则满足传递性
例如,石头剪刀布不满足可排序性。这谁都知道
稳定性
排序后相等元素的位置是否发生变化
如果一定不发生变化,那么我们称它为稳定的排序
如果可能发生变化,那我们称它为不稳定的排序
逆序对
处于逆序关系的一对元素:存在下标 $i,j,(i < j)$,满足 $a_{i} > a_{j}$,称 $(i,j)$ 为一对逆序对
例题:逆序对统计
题目让我们求出 $n$ 个不重复的数中有多少个逆序对
既然这题数据够小,那我们就可以……手打暴力
示例Code:
#include<iostream>
using namespace std;
const int MAXN = 1e3 + 10;
int n,ret,a[MAXN];
int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
for (int i = 1; i <= n; i++){
for (int j = i + 1; j <= n; j++){
ret += a[i] > a[j] ? 1 : 0;
}
}
cout << ret;
return 0;
}
排序函数
C++ STL(Standard Library,标准库)中通过 <algorithm> 头文件中的函数 sort() 和 stable_sort() 预先实现了一些排序算法,只不过,sort()不稳定,而stable_sort()是稳定的(可能后者用的是 $\text{Merge Sort}$ 吧……)。
用法:函数名(起始地址,结束地址,比较器);,表示按比较器函数实现的排序规则对(起始地址,结束地址)做排序,其中比较器是可选参数
sort() 和 stable_sort() 都是基于比较的排序,平均需要 $n \cdot \log(n)$ 次的元素比较和移动,其中 $n$ 表示待排序元素的数量。基于比较的排序时间复杂度至少为 $O(n\log(n))$。
例题:数字排序1
题目让我们从小到大排序,我们就可以用sort函数啦~
示例Code:
#include<iostream>
using namespace std;
const int MAXN = 1e5 + 10;
int n,a[MAXN];
int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
stable_sort(a + 1,a + n + 1);
for (int i = 1; i <= n; i++){
cout << a[i] <<' ';
}
return 0;
}
比较器
用函数实现的自定义比较规则。
在$C++$中,比较器接受两个同类型参数,第一个参数靠前时返回$true$,否则返回$false$(包括相等的情况)
例如:大数靠前的比较器:
bool cmp(int i,int j){
return i > j;
}
例题:数字排序2
题目让我们从大到小排序,我们又可以用sort函数啦~(
当然我们需要一个cmp函数
示例Code:
#include<iostream>
using namespace std;
const int MAXN = 1e5 + 10;
int n,a[MAXN];
bool cmp(int x,int y){
return x > y;
}
int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
stable_sort(a + 1,a + n + 1,cmp);
for (int i = 1; i <= n; i++){
cout << a[i] << ' ';
}
return 0;
}
结构体排序!
重点终于来了(
结构体排序是指开一个结构体,这知道吧,在写一个cmp函数,这也知道吧,然后修改一下cmp,把里面的return语句改一下,假设是这样的:
const int MAXN = 1e5 + 10;
struct Student{
int c,id;
}a[MAXN];
可见这是一个结构体,确切地说,是一个用来存储学生的某某某东西的结构体,然后我们要对它进行排序,怎么排呢?如果你要排的是 $c$(默认小数靠前),那么cmp就这么写:
bool cmp(const Student &a, const Student &b){
return a.c < b.c;
}
然后如果你要排的是$id$(还是小数靠前),就这么写:
bool cmp(const Student &a, const Student &b){
return a.id < b.id;
}
大的靠前的同理
例题1:排序与编号
题目让我们给长度为 $n$ 的数组排序,然后输出排序后的编号,那么我们可以这样,先写一个结构体,里面有$c,id$两个值,还有一个用来存储数据的$Node$类型的$a$数组:
const int MAXN - 1e5 + 10;
struct Node{
int c,id;
}a[MAXN];
然后,就是刚刚讲的结构体排序,因为题目给的是让我们从小到大排序
bool cmp(const Node a, const Node b){
return a.c < b.c;
}
注意:这里要写的是$a.c$,而不是$a.id$,因为不是给$id$排序。
完整示例Code:
#include<iostream>
using namespace std;
const int MAXN = 1e5 + 10;
int n;
struct node{
int id,c;
}a[MAXN];
bool cmp(node x,node &y){
return x.c < y.c;
}
int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i].c;
a[i].id = i;
}
sort(a + 1, a + n + 1,cmp);
for (int i = 1; i <= n; i++){
cout << a[i].id << ' ';
}
return 0;
}
例题2:多关键字排序
题目让我们给同学们的$m$课成绩排序,并按顺序输出排序后的学号,我们还是写结构体排序,注意是有$m$科,所以结构体里面还需要一个数组。
小 a:结构体里是开了数组,但 cmp 函数怎么写?
小 b:谁说cmp函数不能写循环的捏?
$\text{beyoursven}$:典型的只会写板子代码……
示例Code:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 10,maxn = 1e1 + 10;
int n,m;
struct Student{
int km[maxn];
}stu[MAXN];
bool cmp(Student &a,Student &b){
for (int i = 1; i <= m; i++){
if (a.km[i] != b.km[i]){
return a.km[i] > b.km[i];
}
}
return false;
}
int main(){
cin >> n >> m;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
cin >> stu[i].km[j];
}
}
sort(stu + 1,stu + n + 1,cmp);
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
cout << stu[i].km[j] << ' ';
}
cout << '\n';
}
return 0;
}
重载<运算符
排序函数默认使用 < 符号来比较。通过在结构体内重载 < 运算符,可以让排序函数支持结构体排序的比较规则,类似于比较器。
格式:
bool operator < (const Node & i) const{
//...
}
//Node为结构体类型名称,i为对象名
//在大括号中实现比较规则,const表示该运算符不能对成员进行修改操作
例题:区间排序
题目让我们按照左边界和右边界排序,这里分为两种情况:
1,左边界不同
2,左边界相同
这两个东西要写一个||符号,左边界相同和另一个条件(右边界不同)要写&&。
示例Code:
#include<iostream>
using namespace std;
const int MAXN = 1e5 + 10;
int n;
struct node{
int l,r;
bool operator < (const node &k) const {
return l < k.l ||l == k.l && r < k.r;
}
}a[MAXN];
int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i].l >> a[i].r;
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++){
cout << a[i].l << ' ' << a[i].r << '\n';
}
return 0;
}

浙公网安备 33010602011771号