[关闭]
@Dmaxiya 2020-08-24T23:49:12.000000Z 字数 8320 阅读 2056

排序 & 结构体排序练习题解

Hello_World


函数的使用

函数内部实现是快速排序,其功能是将传入的数组进行快速排序,时间复杂度为 ,空间复杂度为 。快排足以应对大多数题目,如果出现卡常数的题目,可以手写基数排序,这里不进行展开。
这里介绍一下几种简单的 函数的用法。

1. 对基本数据类型的数组进行默认排序

函数的默认排序规则是从小到大,如果对基本数据类型数组进行排序,则只要将数组的首地址作为函数的第一个实参,超尾地址作为函数的第二个实参,就可以对数组从第一个参数指向的地址到第二个参数指向的地址之间的元素进行排序。
超尾地址:数组最后一个元素的后一位,例如对于声明为

  1. const int maxn = 100;
  2. int num[maxn];

的整型数组,最后一个元素为

  1. num[maxn - 1];

其超尾地址就是

  1. &num[maxn];

也可以写为

  1. num + maxn;

要对数组所有元素进行排序, 函数的调用方式为

  1. sort(num, num + maxn);

如果以

  1. sort(num, num + n);

调用 函数,则对 数组的前 个元素从小到大排序。

2. 对基本数据类型按特定规则排序

函数的另一个重载形式,可以支持第三个参数:比较函数的传入,它会将比较函数应用在快速排序中,当比较函数返回值为 时,第一个元素被认为比第二个元素小,当比较函数返回值为 时,第一个元素被认为大于等于第二个元素,比较函数可以自定义,但是一定要注意:比较函数必须要定义小于号的意义,而不能定义小于等于号的意义。
以下是对 整型数组所有元素进行绝对值从小到大排序的比较函数定义与 函数的调用方法:

  1. const int maxn = 100;
  2. int num[maxn];
  3. bool cmp(int a, int b) {
  4. return abs(a) < abs(b);
  5. }
  6. sort(num, num + maxn, cmp);

利用比较函数,也可以对字符串进行快速排序:

  1. const int maxn = 100000 + 100;
  2. const int maxm = 1000 + 100;
  3. char str[maxn][maxm];
  4. int Index[maxn];
  5. bool cmp(int a, int b) {
  6. return strcmp(str[a], str[b]) < 0;
  7. }
  8. sort(Index, Index + maxn, cmp);

我们知道,对于长度为 的字符串,排序过程中的赋值操作是很慢的,但是我们可以通过利用字符串做比较,对下标进行赋值,这样排序的速度将会降低 ,其中 为字符串的长度,排序结果存在 数组中,按照下面的方式可以输出正确的排序结果:

  1. for(int i = 0; i < maxn; ++i) {
  2. printf("%s\n", str[Index[i]]);
  3. }

3. 结构体排序

对于基本数据类型, 函数的默认比较是利用小于号,但是对于自定义的结构体,语言本身不会给出结构体小于号的定义,所以我们可以自定义结构体的 比较函数,用第 点所说方法对结构体进行排序,但是我个人强烈建议定义结构体的小于号操作!
定义了结构体的小于号操作,在将结构体数组地址传入 函数时就不必再放入第三个参数, 函数默认利用小于号比较,这里仍然要定义小于号操作,而不要定义小于等于操作,在后面的 中结构体只要定义了小于号,就可以不用管各种乱七八糟的重载了。下面给出日期结构体以月份为第一关键字,日期为第二关键字的定义小于号的写法:

  1. struct Node {
  2. int month;
  3. int day;
  4. };
  5. bool operator<(const Node &a, const Node &b) {
  6. if(a.month == b.month) {
  7. return a.day < b.day;
  8. }
  9. return a.month < b.month;
  10. }

另一种写法为:

  1. struct Node {
  2. int month;
  3. int day;
  4. bool operator<(const Node &tmp) {
  5. if(month == tmp.month) {
  6. return day < tmp.day;
  7. }
  8. return month < tmp.month;
  9. }
  10. };

第一种是将小于号作为结构体的友元函数,第二种是将小于号作为结构体的成员函数,具体的 C++ 语法细节自己去抠,但是请注意:
1. 在写小于号的形参传入时,用上

  1. const Node &

类型,一是加快比较函数速度(引用传递的速度远远快过值传递),二是加强比较准确度(注意 类型值传递过程中的精度损失)。
2. 不要定义小于等于操作,如下:

  1. struct Node {
  2. int x;
  3. };
  4. bool operator<(const Node &a, const Node &b) {
  5. return a.x <= b.x;
  6. }

这将会埋下很深的隐性错误,原因在于, 中无法对该结构体定义等于操作,在 中将用以下方式定义等于操作:

  1. bool operator==(const Node &a, const Node &b) {
  2. return !(a < b) && !(b < a);
  3. }

其中的小于号规则,就是利用你所定义的小于号规则,你可以尝试将以上的代码逻辑运用到下面的程序中模拟一遍结果:

  1. Node a, b;
  2. a.x = 3;
  3. b.x = 3;
  4. if(a == b) {
  5. printf("yes");
  6. } else {
  7. printf("no");
  8. }

输出的结果将会是 ,所以请务必不要定义小于等于操作!

2 月 3 日 排序练习题解

A. Ignatius and the Princess IV

题意

给定 为奇数)个整数,其中有一个数字出现至少 次,问这个数字是多少。

数据范围

题解

将这 个数字进行排序,则这个特殊的数字必然被连续地排在一起,又因为这个连续的数字长度占 ,所以它一定会出现在第 的位置,排序后取位于 位置上的数字就是这个特殊的数字。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 1000000 + 100;
  21. int n;
  22. int num[maxn];
  23. int main() {
  24. #ifdef LOCAL
  25. freopen("test.txt", "r", stdin);
  26. // freopen("out.txt", "w", stdout);
  27. #endif // LOCAL
  28. ios::sync_with_stdio(false);
  29. while(scanf("%d", &n) != EOF) {
  30. for(int i = 0; i < n; ++i) {
  31. scanf("%d", &num[i]);
  32. }
  33. sort(num, num + n);
  34. printf("%d\n", num[n / 2]);
  35. }
  36. return 0;
  37. }

B. As Easy As A+B

题意

组数据,每组数据第一个为 ,表示要对接下来 个数字 按升序排序后输出结果。

数据范围

题解

按照 的默认排序进行排序后输出。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 1000 + 100;
  21. int T, n;
  22. int num[maxn];
  23. int main() {
  24. #ifdef LOCAL
  25. freopen("test.txt", "r", stdin);
  26. // freopen("out.txt", "w", stdout);
  27. #endif // LOCAL
  28. ios::sync_with_stdio(false);
  29. scanf("%d", &T);
  30. while(T--) {
  31. scanf("%d", &n);
  32. for(int i = 0; i < n; ++i) {
  33. scanf("%d", &num[i]);
  34. }
  35. sort(num, num + n);
  36. for(int i = 0; i < n; ++i) {
  37. if(i != 0) {
  38. printf(" ");
  39. }
  40. printf("%d", num[i]);
  41. }
  42. printf("\n");
  43. }
  44. return 0;
  45. }

C. Rank

题意

给出 的学号,以及全班人的学号 和成绩 ,在有并列排名(有可能出现 的排名情况)的情况下,问 的排名。

数据范围

题解

这题只要按照:以分数为主关键字,如果分数相同,学号和 相等排名靠前,就能得到 的排名,这里一定要注意当两个结构体元素相等时要返回 ,否则 函数就会失效。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. int Num, Score;
  21. struct Node {
  22. int num;
  23. int score;
  24. Node() {}
  25. Node(int n, int s) {
  26. num = n;
  27. score = s;
  28. }
  29. };
  30. bool operator<(const Node &a, const Node &b) {
  31. if(a.score == b.score) {
  32. if(a.num == b.num) {
  33. return false;
  34. }
  35. if(a.num == Num) {
  36. return true;
  37. } else if(b.num == Num) {
  38. return false;
  39. } else {
  40. return a.num < b.num;
  41. }
  42. }
  43. return a.score > b.score;
  44. }
  45. int s, n, ans;
  46. vector<Node> vct;
  47. vector<Node>::iterator it;
  48. int main() {
  49. #ifdef LOCAL
  50. freopen("test.txt", "r", stdin);
  51. // freopen("out.txt", "w", stdout);
  52. #endif // LOCAL
  53. ios::sync_with_stdio(false);
  54. while(scanf("%d", &Num) != EOF) {
  55. vct.clear();
  56. while(scanf("%d%d", &n, &s), n != 0 || s != 0) {
  57. vct.push_back(Node(n, s));
  58. if(n == Num) {
  59. Score = s;
  60. }
  61. }
  62. sort(vct.begin(), vct.end());
  63. it = lower_bound(vct.begin(), vct.end(), Node(Num, Score));
  64. printf("%d\n", it - vct.begin() + 1);
  65. }
  66. return 0;
  67. }

2 月 4 日结构体排序练习题解

A. Solving Order

题意

组数据,每组数据有 种气球,第 种气球有 个,按照气球个数输出气球颜色。

数据范围

题解

将气球颜色字符串和气球个数放到一个结构体中,定义结构体的小于号运算符,按照 值大的气球排在前面,排序后输出。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 100;
  21. struct Node {
  22. char str[maxn];
  23. int num;
  24. };
  25. bool operator<(const Node &a, const Node &b) {
  26. return a.num > b.num;
  27. }
  28. int T, n;
  29. Node node[maxn];
  30. int main() {
  31. #ifdef LOCAL
  32. freopen("test.txt", "r", stdin);
  33. // freopen("out.txt", "w", stdout);
  34. #endif // LOCAL
  35. ios::sync_with_stdio(false);
  36. scanf("%d", &T);
  37. while(T--) {
  38. scanf("%d", &n);
  39. for(int i = 0; i < n; ++i) {
  40. scanf("%s%d", node[i].str, &node[i].num);
  41. }
  42. sort(node, node + n);
  43. for(int i = 0; i < n; ++i) {
  44. if(i != 0) {
  45. printf(" ");
  46. }
  47. printf("%s", node[i].str);
  48. }
  49. printf("\n");
  50. }
  51. return 0;
  52. }

B. Design T-Shirt

题意

个人对 个选项投票, 表示第 个人对第 项投的票数,问投票最多的 项分别是哪几项,如果存在票数相同的项,优先选择下标小的项,将这些项按下标从大到小输出。

数据范围

题解

统计每一项获得的票数,将票数和项目下标记录在结构体中,定义结构体的小于号运算符,按照总票数为第一关键字,下标为第二关键字进行排序后,按下标从大到小输出。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 200;
  21. struct Node {
  22. int col;
  23. double num;
  24. };
  25. bool operator<(const Node &a, const Node &b) {
  26. if(a.num == b.num) {
  27. return a.col < b.col;
  28. }
  29. return a.num > b.num;
  30. }
  31. int n, m, k;
  32. double tmp;
  33. Node node[maxn];
  34. int ans[maxn];
  35. int main() {
  36. #ifdef LOCAL
  37. freopen("test.txt", "r", stdin);
  38. // freopen("out.txt", "w", stdout);
  39. #endif // LOCAL
  40. ios::sync_with_stdio(false);
  41. while(scanf("%d%d%d", &n, &m, &k) != EOF) {
  42. memset(node, 0, sizeof(node));
  43. for(int i = 1; i <= n; ++i) {
  44. for(int j = 1; j <= m; ++j) {
  45. scanf("%lf", &tmp);
  46. node[j].num += tmp;
  47. node[j].col = j;
  48. }
  49. }
  50. sort(node + 1, node + m + 1);
  51. for(int i = 1; i <= k; ++i) {
  52. ans[i] = node[i].col;
  53. }
  54. sort(ans + 1, ans + k + 1);
  55. for(int i = k; i > 0; --i) {
  56. if(i != k) {
  57. printf(" ");
  58. }
  59. printf("%d", ans[i]);
  60. }
  61. printf("\n");
  62. }
  63. return 0;
  64. }

C. Milk

题意

每天都要喝 牛奶,如果当天牛奶少于 或者牛奶超过 天,他都会把牛奶扔掉。今天 要在 种牛奶中挑一种,按照单价(平均每天的价格)便宜的买,如果两种牛奶单价相同,则买容量大的。

数据范围

题解

将牛奶的品牌、单价、容量放入一个结构体中,按题意计算出每种牛奶的单价,再按题意给的规则排序,输出第一项牛奶的品牌。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 200;
  21. struct Node {
  22. char str[maxn];
  23. double price;
  24. double vol;
  25. double per;
  26. Node() {}
  27. void Set() {
  28. int day = min(vol / 200, 5.0);
  29. per = price / day;
  30. }
  31. };
  32. bool operator<(const Node &a, const Node &b) {
  33. if(a.per == b.per) {
  34. return a.vol > b.vol;
  35. }
  36. return a.per < b.per;
  37. }
  38. int T, n;
  39. Node node[maxn];
  40. int main() {
  41. #ifdef LOCAL
  42. freopen("test.txt", "r", stdin);
  43. // freopen("out.txt", "w", stdout);
  44. #endif // LOCAL
  45. ios::sync_with_stdio(false);
  46. scanf("%d", &T);
  47. while(T--) {
  48. scanf("%d", &n);
  49. for(int i = 0; i < n; ++i) {
  50. scanf("%s%lf%lf", node[i].str, &node[i].price, &node[i].vol);
  51. node[i].Set();
  52. }
  53. sort(node, node + n);
  54. printf("%s\n", node[0].str);
  55. }
  56. return 0;
  57. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注