【C++修行之道】竞赛常用库函数(sort,min和max函数,min_element和max_element、nth_element)

简介: 【C++修行之道】竞赛常用库函数(sort,min和max函数,min_element和max_element、nth_element)



一、sort

1.1sort简介

  • sort函数包含在头文件<algorithm>中。
  • 在使用前需要#include <algorithm>或使用万能头文件。
  • sort是C++标准库中的一个函数模板,用于对指定范围内的元素进行排序。
  • sort算法使用的是快速排序 (QuickSort) 或者类似快速排序的改进算法,具有较好的平均时间复杂度,一般为O(nlogn)

语法

Sort(start,end,cmp)

参数

(1)start表示要排序数组的起始地址;

(2)end表示数组结束地址的下一位;

(3)cmp用于规定排序的方法,可不填,默认升序。

功能

sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。

一般是直接对数组进行排序,例如对数组a[10]排序,sort(a,a+10)。而sort函数的强大之处在可与cmp函数结合使用,即自定义排序:如果你想按照特定的顺序排序,可以传递一个自定义的比较函数或lambda表达式给sort()。这个函数应该接受两个参数,并返回一个布尔值,指示第一个参数是否应该在排序后位于第二个参数之前。

相对于普通的排序算法,sort()函数在快速排序(详见C++快速排序)的基础上,又进行了优化,时间复杂度为n*log2(n),执行效率较高。

适用容器

sort()函数适用于数组和提供了随机访问迭代器的大多数STL容器,如vector、deque等。对于不支持随机访问迭代器的容器(如list、forward_list),应使用list容器自己的sort()成员函数。

int main()
{
  //sort(起始地址,   结束地址的下一位, *比较函数);
  //   迭代器begin()  end()         默认用小于号<
  int a[1000];
  int n;
  //读取数组大小
  cin >> n;
  //读取数组元素
  for (int i = 1; i <= n; ++i)cin >> a[i];
  //对数组进行排序
  sort(a + 1, a + n + 1);
  //    a[1]    a[n+1]  [1,n+1) 左闭右开
  //输出
  for (int i = 1; i <= n; ++i)cout << a[i] << ' ';
}

1.2sort的用法

std::sort(begin, end);

begin和end是输入序列的起始迭代器和结束迭代器。需要注意的是,end迭代器指向的是序列尾部的"过去位置",即最后一个有效元素之后的位置。

int main()
{
  //初始化v
  vector<int>v = { 5,1,3,9,11 };
  //        begin  v[0]    v[4]  end()
  //对数组进行排序
  sort(v.begin(), v.end());
  //输出
  //for (int i = 0; i < v.size(); ++i)cout << v[i] << ' ';
  for (auto& i : v)cout << i << ' ';
  return 0;
}

1.3自定义比较函数

使用sort()我们不仅仅可以从大到小排或者从小到大排,还可以按照一定的准则进行排序。比如说我们按照每个数的个位进行从大到小排序,我们就可以根据自己的需求来写一个函数作为排序的准则传入到sort()中。

//sort默认使用小于号进行排序,如果想要自定义比较规则,
//可以传入第三个参数,可以是函数或lambda表达式(匿名函数)
bool cmp(const int& u, const int& v)
{
  return u > v;
}
int main()
{
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  //初始化
  vector<int> v = { 5,1,3,9,11 };
  //对数组进行排序,降序排序
  sort(v.begin(), v.end(),cmp);
  //输出
  /*for (int i = 0; i < v.size(); ++i)cout << v[i] << ' ';*/
  for (auto& i : v)
    //就是v中的数据
  {
    cout << i << ' ' ;
  }
}

sort默认使用小于号进行排序,如果想要自定义比较规则
可以传入第三个参数,可以是函数或lambda表达式(匿名函数)。

int main()
{
  //初始化v
  vector<int>v = { 5,1,3,9,11 };
  //对数组进行排序,降序排序
  sort(v.begin(), v.end(), [](const int& u, const int& v)
  {
    return u > v;
  });
  
  //输出
  //for (int i = 0; i < v.size(); ++i)cout << v[i] << ' ';
  for (auto& i : v)
    //就是v中的数据
  {
    cout << i << ' ' ;
  }
  return 0;
}

结构体可以将小于号重载后进行排序,当然,用前面的方法也是可行的

struct Node
{
  int u, v;
  bool operator<(const Node& m)const
    //重载的operator<是一个成员函数,
    //它接受一个const Node&类型的参数(即对另一个Node对象的常量引用),
    //并返回一个bool类型的结果。
  {
    //以u为第一关键字,v为第二关键字排序
    return u == m.u ? v < m.v : u < m.u;
  }
};
#include <iostream>
using namespace std;
int main()
{
  int n; cin >> n;
  return 0;
}

示例

#include<iostream>  
#include<string>  
#include<algorithm>  
using namespace std;  
  
struct Student{  
  string name;  // 学生姓名  
  double score[4];  // 学生四门课的成绩  
};  
  
// 比较函数,用于sort排序,按照平均成绩从高到低排序  
bool cmp_score(const Student &x, const Student &y){  
  double average_x = 0.0, average_y = 0.0;  
  for(int i = 0; i < 4; i++){  
    average_x += x.score[i];  
    average_y += y.score[i];  
  }  
  average_x /= 4;  
  average_y /= 4;  
  return average_x > average_y;  
}  
  
int main(){  
  Student stu[3];  // 存储三个学生的信息  
    
  // 输入三个学生的姓名和四门课的成绩  
  for(int i = 0; i < 3; i++){  
    cin >> stu[i].name;  
    for(int j = 0; j < 4; j++){  
      cin >> stu[i].score[j];  
    }  
  }  
    
  // 使用sort函数,按照平均成绩从高到低排序  
  sort(stu, stu + 3, cmp_score);  
    
  // 输出排序后的学生信息  
  for(int i = 0; i < 3; i++){  
    cout << stu[i].name << " ";  
    for(int j = 0; j < 4; j++){  
      cout << stu[i].score[j] << " ";  
    }  
    cout << endl;  // 换行  
  }  
    
  return 0;  
}

1265蓝桥题 —— 排序

#include <bits/stdc++.h> // 包含了C++标准库中的大部分头文件  
  
using namespace std; // 使用标准命名空间std  
  
const int N = 5e5 + 3; // 定义一个常量N,其值为500003,作为数组a的最大可能大小  
int a[N]; // 定义一个全局数组a,大小为N  
  
int main() 
{  
  int n; cin >> n; // 输入一个整数n,表示数组a中实际元素的数量  
  for (int i = 1; i <= n; ++i) cin >> a[i]; 
    // 从a[1]开始(而不是通常的a[0]),输入n个整数到数组a中  
  
  sort(a + 1, a + 1 + n); // 对数组a中从a[1]到a[n]的元素进行排序  
  
  // 以升序打印数组a中的元素  
  for (int i = 1; i <= n; ++i)  
    cout << a[i] << " \n"[i == n]; 
        // 打印每个元素和一个空格,如果i等于n(即最后一个元素),则打印换行符  
    // 这里使用了字符串字面量" \n"的数组索引技巧:
        // 当i==n时,[i==n]求值为[1],选择'\n';否则为[0],选择' '  
  
  // 以降序打印数组a中的元素  
  for (int i = n; i >= 1; --i)  
    cout << a[i] << " \n"[i == 1];
 // 类似地,打印每个元素和一个空格,如果i等于1(即最后一个要打印的元素),则打印换行符  
  
  return 0; 
}

二、min和max函数

  • min和max函数
  • min(a,b)返回a和b中较小的那个值,只能传入两个值,或传入一个列表
  • 例如:
  • min(3, 5) = 3
  • min({1, 2, 3,4)) = 1
  • max(a,b)返回a和b中较大的那个值,只能传入两个值,或传入一个列表
  • 例如:
  • max(7,5)= 7
  • max([1, 2,3,4) = 4
  • 时间复杂度为O(1),传入参数为数组时时间复杂度为O(n),n为数组大小。
  • min,max函数是在取最值操作时最常用的操作。

三、min_element和max_element

min_element 和 max_element

头文件:#include<algorithm>

作用:返回容器中最小值和最大值的指针。max_element(first,end,cmp);其中cmp为可选择参数!

  • min_element(st,ed)返回地址[st,ed)中最小的那个值的下标(选代器),传入参数为两个地址或迭代器。
  • max_element(st,ed)返回地址[st,ed)中最大的那个值的下标 (选代器),传入参数为两个地址或迭代器。
  • 时间复杂度均为O(n),n为数组大小(由传入的参数决定)。
int main()
{
  //初始化
  vector<int>v = { 5,1,3,9,11 };
  //         [      )
  //输出最大的元素,*表示解引用,即通过地址(迭代器)得到值
  cout << *max_element(v.begin(), v.end()) << '\n';
}

497蓝桥题 —— 成绩分析


用户登录

#include <bits/stdc++.h> 
using namespace std;      
  
const int N = 1e4 + 9;    
int a[N];                 
  
int main() // 主函数  
{  
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 加速输入输出流  
  int n; cin >> n; 
  for (int i = 1; i <= n; ++i) cin >> a[i]; 
  
  int mx = a[1], mi = a[1]; // 初始化最大值mx和最小值mi为数组的第一个元素a[1]  
  for (int i = 1; i <= n; ++i) // 遍历数组a中的所有元素  
  {  
    mx = max(mx, a[i]); // 更新最大值mx  
    mi = min(mi, a[i]); // 更新最小值mi  
  }  
  
  cout << mx << '\n' << mi << '\n'; // 输出最大值和最小值,每个值后面跟一个换行符  
  
  long long sum = 0; // 定义一个长整型变量sum,用于存储数组a中所有元素的总和  
  for (int i = 1; i <= n; ++i) sum += a[i]; // 遍历数组a,计算所有元素的总和  
  
  cout << fixed << setprecision(2) << 1.0 * sum / n << '\n'; // 输出平均值,保留两位小数  
  // 注意:这里使用1.0 * sum将sum转换为浮点数,以确保进行浮点数除法  
  
  return 0; // 程序执行成功,返回0  
}

四、nth_element

  • nth_element()进行部分排序,返回值为void()
  • 传入参数为三个地址或迭代器。其中第二个参数位置的元素将处于正确位置,其他位置元素的顺序可能是任意的,但前面的都比它小,后面的都比它大
  • nth_element()是c++的STL库中的函数,作用是将数组中第k小的整数放在区间第k个位置
  • 比如vector<int> nums = {9, 7, 5, 11, 12, 2, 14, 3, 10, 6};
  • nth_element 会重新排列序列,使得第5小的元素位于正确的位置(索引为4的位置),且该元素之前的所有元素都不大于它,之后的元素都不小于它。
  • 使用一次nth_element()的时间复杂度为O ( n )。
int main()
{
  // 初始化一个包含7个整数的vector  
  vector<int> v = { 5,1,7,3,10,18,9 };
  // 使用nth_element进行部分排序  
  // 将v中的元素重新排列,使得v[3]位置上的元素位于排序后应在的位置  
  // v[0]到v[2]的元素都不大于v[3],v[4]到v[6]的元素都不小于v[3]  
  nth_element(v.begin(), v.begin() + 3, v.end());
  // 输出vector中的元素  
  for (auto& i : v)
    cout << i << ' '; // 注意:这里应该使用' '空格而不是'\n'换行符  
  return 0;
}

今天就先到这了!!!

看到这里了还不给博主扣个:

⛳️ 点赞☀️收藏 ⭐️ 关注!

你们的点赞就是博主更新最大的动力!

有问题可以评论或者私信呢秒回哦。

相关文章
|
4月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
109 0
|
7月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
397 6
|
12月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
459 6
|
8月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
184 0
|
6月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
216 12
|
7月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
140 16
|
8月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
7月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。