题解 | #成绩排序-两种实现办法-含解释#

题解 | #成绩排序-两种实现办法-含解释#

描述

题目描述

首先我们是有 T组数据 ,接下来我们每组数据输入一个 n 代表的是我们有 n位同学的成绩需要我们来进行一个排序,接下来输入一个 op 这个代表的就是我们按照什么规则来排序

当 op == 0 时,代表我们排序要按照 从高到低来排序

当 op == 1 时,代表我们排序要按照 从低到高来排序

接下来就是 n 组数据,每组数据的 第一个是姓名, 第二个是成绩

样例解释

3

1

fang 90

yang 50

ning 70

3

0

moolgouua 43

aebjag 87

b 67

首先第一个 3 代表的是代表的是有三组数据,接下来的 1 是让我们把接下来的三个成绩按照从低到高的顺序来进行一个排序,那么我们经过从低到高的排序后,我们可以得到第一个样例输出

yang 50

ning 70

fang 90

然后我们对第二个样例进行一个解释, 3 代表的是有三组数据,接下来 0 代表的是我们把接下来的三组数据按照成绩从高到低排序,排序后我们可以得到这么一个结果

aebjag 87

b 67

moolgouua 43

这道题我们可以看出,我们要做的就是首先把姓名跟成绩对应存储下来,然后进行一个排序,最后我们把我们的思路进行一个化简,发现这个题是一个考察结构体排序的题目

知识点: 结构体排序

难度: 两星

题解:

解题思路:

这道题我们发现了是考察我们的一个结构体排序的知识点,但是这里面有一个需要我们注意的问题:

如果有两位同学的成绩是相同的,那么我们最后输出的顺序要按照他们输入的顺序来输出

对于这道题目来讲,我们存储我们的成绩对应姓名,使用结构体的时候空间复杂度是 O(n) 的,时间复杂度也是 O(n) 的,但是对于我们的排序来讲使用不同的排序的时候,他的时间复杂度是不一样的,假设我们使用最为暴力的双重 for 循环的排序做法,那么我们总体的时间复杂度就是 n2n ^ 2n2 的,因为一个程序的时间复杂度是取决于他的最高的时间复杂度的

解法一 :暴力解法

我们采用双重 for 循环的方式,然后排序成绩以及他的id,我们的代码实现如下

时空复杂度分析

首先我们开辟了结构体数组用以存储我们的姓名,成绩,以及输入的顺序,这里我们输入的时间复杂度是 O(n) 的,然后空间复杂度是 3*n 的,但是在算法竞赛中,我们前面的常数是忽略的,所以我们这个的空间复杂的是 O(n) 的,然后我们的暴力排序算法经过了 n * (n - 1) / 2 次运算的,然后计算时间复杂度就是n2n ^ 2n2的时间复杂度,最后这种暴力求解的方法,空间复杂度是O(n) 的,时间复杂度是 n2n ^ 2n2的

#include

using namespace std;

const int N = 210;

struct node {

string name;

int val, id;

} a[N];

int main() {

ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

int n;

while(cin >> n) { // 多组输入我们的n组数据

int op;

cin >> op; // 输入我们的排序规则

for (int i = 1; i <= n; i++) {

cin >> a[i].name >> a[i].val;

a[i].id = i;

}

// 输入我们的 n 组的名字以及成绩,最后把id赋值上去

if (op == 1) {

for (int i = 1; i <= n; i++) {

for (int j = i + 1; j <= n; j++) {

if (a[i].val > a[j].val) swap(a[i], a[j]); // 首先我们判断如果我们的成绩前面的比后面的大,那么我们交换

else if (a[i].val == a[j].val) {

if (a[i].id > a[j].id) swap(a[i], a[j]);

// 如果我们的成绩相同,前者的id比后者的id大,我们也要交换

}

}

}

} else {

for (int i = 1; i <= n; i++) {

for (int j = i + 1; j <= n; j++) {

if (a[i].val < a[j].val) swap(a[i], a[j]); // 首先我们判断如果我们的成绩前面的比后面的小,那么我们交换

else if (a[i].val == a[j].val) {

if (a[i].id > a[j].id) swap(a[i], a[j]);

// 如果我们的成绩相同,前者的id比后者的id大,我们也要交换

}

}

}

// 这里是如果两者的成绩相同,那么返回id较小的,否则返回成绩大的

}

// 我们对两次进行一个排序

for (int i = 1; i <= n; i++) {

cout << a[i].name << " " << a[i].val << endl;

}

// 输出我们排序后的结果

}

return 0;

}

图解算法

解法二 : 快速排序 - 自定义排序函数

时空复杂度分析

这里我们要追求更快的处理速度,那么我们要采取更快的一个排序的方式,这里我们选择了快速排序,这次我们采用的算法的空间复杂度是O(n) 的,但是我们的时间复杂度使用的是快速排序,快速排序的时间复杂度是O(nlogn) 的,那么我们这种快速排序搭配结构体的算法的总体的时间复杂度就是 O(nlogn) 的,空间复杂度就是O(n) 的,可能会有小伙伴疑问,为什么输入的时间复杂度O(n) 我们在这里面不考虑呢?

因为在我们的算法竞赛中,一个算法的时间复杂度取决于的是它最慢的一个时间,换种理解方式就是,在n很大的时候,我们的小的地方是可以忽略不记的,所以我们时间复杂度取得是一个程序中的瓶颈的时间复杂度

这里我给出两种写法,第一种是自己定义比较函数一般成为 cmp

#include

using namespace std;

const int N = 210;

struct node {

string name;

int val, id;

} a[N];

bool cmp1(node wa, node wb) {

if (wa.val == wb.val) return wa.id < wb.id;

return wa.val < wb.val;

}

// cmp1这里是如果两者的成绩相同,那么返回id较小的,否则返回成绩小的

bool cmp2(node wa, node wb) {

if (wa.val == wb.val) return wa.id < wb.id;

return wa.val > wb.val;

}

// cmp2这里是如果两者的成绩相同,那么返回id较小的,否则返回成绩大的

int main() {

ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

int n;

while(cin >> n) { // 输入有多少组待排序的数据

int op;

cin >> op; // 输入排序规则

for (int i = 1; i <= n; i++) {

cin >> a[i].name >> a[i].val;

a[i].id = i;

}

// 将我们的姓名和成绩输入,并且记录下来id,就是输入的顺序

if (op == 1) {

sort(a + 1, a + n + 1, cmp1);

// 以cmp1的规则排序

} else {

sort(a + 1, a + n + 1, cmp2);

// 以cmp2的规则排序

}

for (int i = 1; i <= n; i++) {

cout << a[i].name << " " << a[i].val << endl;

}

}

return 0;

}

快速排序 - 匿名函数 (c++11及以后)

第二种就是用到了c++11出现的匿名函数的这个语法

#include

using namespace std;

const int N = 210;

struct node {

string name;

int val, id;

} a[N];

int main() {

ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

int n;

while(cin >> n) {

int op;

cin >> op;

for (int i = 1; i <= n; i++) {

cin >> a[i].name >> a[i].val;

a[i].id = i;

}

if (op == 1) {

sort(a + 1, a + n + 1, [](node wa, node wb) -> bool {

if (wa.val == wb.val) return wa.id < wb.id;

return wa.val < wb.val;

});

// 这里是如果两者的成绩相同,那么返回id较小的,否则返回成绩小的

} else {

sort(a + 1, a + n + 1, [](node wa, node wb) -> bool {

if (wa.val == wb.val) return wa.id < wb.id;

return wa.val > wb.val;

});

// 这里是如果两者的成绩相同,那么返回id较小的,否则返回成绩大的

}

for (int i = 1; i <= n; i++) {

cout << a[i].name << " " << a[i].val << endl;

}

}

return 0;

}

相关推荐

vivoiqoo手机 iqoo新手机第一次充电要充多久
365cc彩票老版

vivoiqoo手机 iqoo新手机第一次充电要充多久

📅 07-05 👁️ 2229
2023年中国泥鳅养殖现状及分省市产量格局统计[图]
日博365官网网址多少

2023年中国泥鳅养殖现状及分省市产量格局统计[图]

📅 11-04 👁️ 3224
有什么食物能「撑死」人,但几乎没热量?
365cc彩票老版

有什么食物能「撑死」人,但几乎没热量?

📅 07-03 👁️ 7734