突破编程_C++_STL教程( sort 算法)

1 std::sort 算法的概念与用途

std::sort 是 C++ 标准库中的一个通用排序算法,它属于 头文件的一部分。该算法设计得非常通用和灵活,能够对各种类型的序列进行排序,包括数组、向量、列表、甚至自定义容器等。std::sort 的核心在于其内部实现的排序算法,它通常是高效的快速排序、归并排序或者它们的某种组合。

概念

std::sort 的基本概念在于它接受两个迭代器参数,分别表示要排序序列的起始位置和结束位置(不包含结束位置所指向的元素)。这两个迭代器定义了需要排序的范围。算法会根据这个范围,对序列中的元素进行排序。

默认情况下,std::sort 执行的是升序排序,即较小的元素会排在前面,较大的元素会排在后面。然而,std::sort 也支持自定义排序规则,通过提供一个比较函数或可调用对象作为第三个参数,可以实现降序排序或者根据元素的特定属性进行排序。

排序过程
在排序过程中,std::sort 会不断地将序列划分为更小的部分,并对这些部分进行排序,直到整个序列都排好序。具体的排序策略(如快速排序或归并排序)会根据输入数据的大小和特性自动选择,以尽可能减少排序所需的时间。

std::sort 的时间复杂度通常是 O(n log n),其中 n 是要排序的元素数量。这意味着对于大型数据集,std::sort 通常能够提供相当高效的排序性能。

用途
std::sort 在实际编程中用途广泛,几乎任何需要对数据进行排序的场景都可以使用它。以下是一些常见的用途示例:

  • 数据预处理:在数据分析或机器学习的任务中,经常需要对数据集进行排序,以便后续处理或分析。
  • 查找操作优化:排序后的数据可以更快地执行查找操作,例如二分查找算法就依赖于排序后的序列。
  • 数据结构维护:某些数据结构(如二叉搜索树)在插入新元素前需要对已有元素进行排序。
  • 可视化与展示:排序数据有助于更直观地展示信息,例如在图表或报告中。
  • 算法实现:排序是很多其他算法的基础步骤,例如排序算法本身、图算法、选择算法等。

通过使用 std::sort,开发者可以专注于实现他们的算法逻辑,而无需担心排序算法的具体实现。这样不仅可以提高开发效率,还可以确保排序操作的正确性和性能。

2 std::sort 算法基础

2.1 std::sort 算法的定义与语法

(1)定义

std::sort 是一种通用的排序算法,它基于比较操作对序列中的元素进行排序。该算法不依赖于具体的容器类型,只要提供了合适的迭代器,就可以对任意类型的序列进行排序。std::sort 的实现通常基于高效的排序算法,如快速排序或归并排序,以提供较好的性能。

(2)语法

std::sort 的语法如下:

template< class RandomIt >  
void sort( RandomIt first, RandomIt last );  template< class RandomIt, class Compare >  
void sort( RandomIt first, RandomIt last, Compare comp );
  • RandomIt 是一个随机访问迭代器类型,用于指定要排序的序列的开始和结束位置。
  • first 和 last 是随机访问迭代器,分别指向要排序序列的起始位置和结束位置的下一个位置。
  • Compare 是一个可选的比较函数或可调用对象类型,用于定义排序规则。
  • comp 是一个可选的比较函数或可调用对象,用于自定义排序规则。如果不提供 comp,则默认使用 operator< 进行升序排序。

(3)返回值

std::sort 函数没有返回值,它的作用是对指定范围内的元素进行排序。排序完成后,序列中的元素将按照指定的排序规则重新排列。

2.2 std::sort 算法的使用示例

下面是一个使用 std::sort 对整数向量进行升序排序的示例:

#include <iostream>  
#include <vector>  
#include <algorithm>  int main() {  std::vector<int> numbers = {5, 2, 8, 1, 9};  // 使用 std::sort 进行升序排序  std::sort(numbers.begin(), numbers.end());  // 输出排序后的结果  for (int num : numbers) {  std::cout << num << ' ';  }  std::cout << std::endl;  return 0;  
}

输出将是:

1 2 5 8 9

如果要进行降序排序,可以提供一个自定义的比较函数:

#include <iostream>  
#include <vector>  
#include <algorithm>  bool compareDescending(int a, int b) {  return a > b;  
}  int main() {  std::vector<int> numbers = {5, 2, 8, 1, 9};  // 使用 std::sort 和自定义比较函数进行降序排序  std::sort(numbers.begin(), numbers.end(), compareDescending);  // 输出排序后的结果  for (int num : numbers) {  std::cout << num << ' ';  }  std::cout << std::endl;  return 0;  
}

输出将是:

9 8 5 2 1

这个降序排序的示例定义了一个名为 compareDescending 的比较函数,它接受两个整数参数并返回 true 如果第一个参数大于第二个参数。然后将这个函数作为第三个参数传递给 std::sort,以便按照降序对向量中的元素进行排序。

3 std::sort 算法的高级用法

3.1 使用 std::greater 降序排序

使用 std::greater 进行降序排序是 C++ 标准库提供的一种简单而直接的方法。std::greater 是一个预定义的函数对象(也称为仿函数),它接受两个参数并返回一个布尔值,指示第一个参数是否大于第二个参数。当与 std::sort 结合使用时,std::greater 可以实现降序排序。

下面是一个使用 std::greater 进行降序排序的示例:

#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <functional> // 需要包含这个头文件来使用 std::greater  int main() {  std::vector<int> numbers = {5, 2, 8, 1, 9};  // 使用 std::sort 和 std::greater 进行降序排序  std::sort(numbers.begin(), numbers.end(), std::greater<int>());  // 输出排序后的结果  for (int num : numbers) {  std::cout << num << ' ';  }  std::cout << std::endl;  return 0;  
}

这个例子首先创建了一个包含整数的向量 numbers。然后,使用 std::sort 函数对该向量进行排序。std::sort 的第三个参数是 std::greater<int>(),它告诉 std::sort 使用降序排序规则。std::greater<int>() 是一个函数对象,它比较两个 int 类型的值,并返回 true 如果第一个值大于第二个值。

上面代码的输出为:

9 8 5 2 1

需要注意的是,对于基本数据类型(如 int、float、double 等),std::greater 默认已经特化(specialized),因此可以直接传递 std::greater<int>() 而不需要显式提供比较操作。然而,对于自定义类型,则需要提供自定义的比较逻辑或者重载比较操作符(如 operator>)以便与 std::greater 配合使用。

3.2 稳定排序 std::stable_sort 的使用

std::stable_sort 是 C++ 标准库 <algorithm> 头文件中提供的另一个排序算法。与 std::sort 不同,std::stable_sort 在排序时保持了相等元素的相对顺序,即排序是稳定的。这意味着如果原始序列中有两个或更多的相等元素,那么 std::stable_sort 排序后这些元素的相对顺序不会改变。

下面是 std::stable_sort 的详细使用说明:

语法

template< class RandomIt >  
void stable_sort( RandomIt first, RandomIt last );  template< class RandomIt, class Compare >  
void stable_sort( RandomIt first, RandomIt last, Compare comp );
  • RandomIt:随机访问迭代器类型,用于指定要排序序列的开始和结束位置。
  • first 和 last:随机访问迭代器,分别指向要排序序列的起始位置和结束位置的下一个位置。
  • Compare:可选的比较函数或可调用对象类型,用于定义排序规则。
  • comp:可选的比较函数或可调用对象,用于自定义排序规则。如果不提供 comp,则默认使用 operator< 进行升序排序。

使用示例

假设有一个自定义类型 Person,它包含姓名和年龄两个成员变量。现在需要根据年龄对这个类型的对象进行排序,同时保持年龄相同的对象的相对顺序不变。

首先,定义 Person 类型:

#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <string>  struct Person {  std::string name;  int age;  Person(const std::string& name, int age) : name(name), age(age) {}  // 为了输出方便,重载 << 运算符  friend std::ostream& operator<<(std::ostream& os, const Person& p) {  os << p.name << " (" << p.age << ")";  return os;  }  
};

然后,创建一个 Person 对象的向量,并使用 std::stable_sort 对其进行排序:

int main() {  std::vector<Person> people = {  {"Alice", 25},  {"Bob", 20},  {"Charlie", 25},  {"David", 30},  {"Eve", 20}  };  // 使用 lambda 表达式作为比较函数,根据年龄进行升序排序  std::stable_sort(people.begin(), people.end(), [](const Person& a, const Person& b) {  return a.age < b.age;  });  // 输出排序后的结果  for (const auto& person : people) {  std::cout << person << std::endl;  }  return 0;  
}

在这个例子中,使用了 C++11 的 lambda 表达式来定义比较函数。这个 lambda 表达式接受两个 Person 对象作为参数,并返回 a.age < b.age 的结果,即按照年龄进行升序排序。由于使用了 std::stable_sort,即使 Alice 和 Charlie 的年龄相同,它们在排序后的序列中的相对顺序也会保持不变。

上面代码的输出为:

Bob (20)
Eve (20)
Alice (25)
Charlie (25)
David (30)

注意,Bob 和 Eve 的相对顺序以及 Alice 和 Charlie 的相对顺序在排序后都没有改变。这就是 std::stable_sort 与 std::sort 的主要区别之一。

如果想要按照年龄降序排序,只需调整 lambda 表达式中的比较逻辑即可:

std::stable_sort(people.begin(), people.end(), [](const Person& a, const Person& b) {  return a.age > b.age;  
});

这样,年龄较大的 Person 对象将会排在前面。

性能考虑

std::stable_sort 的平均时间复杂度通常是 O(n log n),其中 n 是待排序元素的数量。尽管与 std::sort 的时间复杂度相同,但由于 std::stable_sort 需要额外的空间来保持稳定性,并且在某些实现中可能使用了不同的算法,因此它通常会比 std::sort 慢一些。在不需要保持相等元素顺序的场合下,使用 std::sort 会更加高效。

总体而言,std::stable_sort 是一个强大且有用的排序算法,特别是在处理包含重复元素的序列时。通过自定义比较函数或可调用对象,可以很容易地对自定义类型的对象进行排序。

4 std::sort 算法应用与自定义类型

下面是一个 std::sort 算法应用于自定义类型的例子:

首先,定义一个自定义类型,比如一个表示学生的结构体:

#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <string>  struct Student {  std::string name;  int score;  Student(const std::string& name, int score) : name(name), score(score) {}  // 重载输出运算符以便能方便地打印 Student 对象  friend std::ostream& operator<<(std::ostream& os, const Student& s) {  os << s.name << ": " << s.score;  return os;  }  
};

然后,创建一个 Student 对象的向量,并使用 std::sort 对其进行排序。为了排序,需要提供一个比较函数或函数对象。这里提供一个 lambda 表达式作为比较函数:

int main() {  std::vector<Student> students = {  {"Alice", 90},  {"Bob", 85},  {"Charlie", 92},  {"David", 88},  {"Eve", 90}  };  // 使用 lambda 表达式作为比较函数,按分数降序排序  std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {  return a.score > b.score; // 降序排序  });  // 输出排序后的结果  for (const auto& student : students) {  std::cout << student << std::endl;  }  return 0;  
}

上面代码的输出为:

Charlie: 92
Alice: 90
Eve: 90
David: 88
Bob: 85

在这个例子中,lambda 表达式 [](const Student& a, const Student& b) { return a.score > b.score; } 被用作比较函数,它比较两个 Student 对象的 score 成员。由于返回 a.score > b.score,这会导致 std::sort 以降序方式对学生进行排序。

如果想以升序排序,只需将比较函数中的 > 改为 < 即可:

std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {  return a.score < b.score; // 升序排序  
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/783652.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos 7 安装磐维(PanWeiDB)数据库(单机)

前置环境准备 文件系统环境要求 文件系统环境所要求的扇区必须为512bytes&#xff0c;查看方法如下&#xff1a; [rootdevops-core-highapp3-b-32 ~]#df -h /apps/ [rootdevops-core-highapp3-b-32 ~]#ll /dev/mapper/vg--docker-lvapp [rootdevops-core-highapp3-b-32 ~]#f…

EfficientNetV2:谷歌又来了,最小的模型,最高的准确率,最快的训练速度 | ICML 2021

论文基于training-aware NAS和模型缩放得到EfficientNetV2系列&#xff0c;性能远优于目前的模型。另外&#xff0c;为了进一步提升训练速度&#xff0c;论文提出progressive learning训练方法&#xff0c;在训练过程中同时增加输入图片尺寸和正则化强度。从实验结果来看&#…

【docker】nexus 本地 maven配置

1、这篇文章中说明了如何搭建私服 【docker】搭建Nexus私服-CSDN博客文章浏览阅读2次。4、点击登陆&#xff08;账号&#xff1a;admin 秘密&#xff1a;在容器内 /nexus-data/admin.password 文件中)注意我的端口号是 10002&#xff0c;注意你的端口号。7、设置maven-central…

MSTP环路避免实验(华为)

思科设备参考&#xff1a;MSTP环路避免实验&#xff08;思科&#xff09; 一&#xff0c;技术简介 MSTP&#xff08;多生成树协议&#xff09;&#xff0c;MSTP解决了STP和RSTP没有考虑vlan的问题&#xff0c;STP和RSTP将所有的vlan共享为一个生成树实例&#xff0c;无法实现…

获取电商数据的几种方法分享

在数字化时代&#xff0c;电商数据已经成为企业决策的重要依据。无论是市场趋势的洞察、用户行为的分析&#xff0c;还是产品优化和营销策略的制定&#xff0c;都离不开电商数据的支持。本文将分享几种获取电商数据的有效方法&#xff0c;力求在干货满满的同时&#xff0c;也不…

Linux系统网络的实时性评估

目录 1.使用 cyclictest 测试系统实时性2.测试系统通信实时性2.1 PingPlotter2.2 使用 ping 测试通讯实时性 3. 使用 iperf 测试带宽4.网络性能测试 1.使用 cyclictest 测试系统实时性 安装cyclictest sudo apt-get update sudo apt-get install rt-testscyclictest -p 99 -i…

代码第三十六天:需要添加的硬币的最小数量

需要添加的硬币的最小数量 题目要求&#xff1a; 解题思路 为方便描述&#xff0c;把 0 也算作可以得到的数。 假设现在得到了区间 [ 0 , s − 1 ] [0,s−1] [0,s−1] 中的所有整数&#xff0c;如果此时遍历到整数 x c o i n s [ i ] xcoins[i] xcoins[i]&#xff0c;那么…

win10 安装kubectl,配置config连接k8s集群

安装kubectl 按照官方文档安装&#xff1a;https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/ curl安装 &#xff08;1&#xff09;下载curl安装压缩包: curl for Windows &#xff08;2&#xff09;配置环境变量&#xff1a; 用户变量&#xff1a; Path变…

Python之Opencv教程(2):图像边缘检测

1、什么是边缘检测 OpenCV中的边缘检测是一种常见的图像处理技术&#xff0c;用于检测图像中物体边缘的位置。常用的边缘检测算法包括Sobel算子、Scharr算子、Laplacian算子和Canny边缘检测算法等。下面将介绍使用OpenCV实现这些边缘检测算法的方法。 2、边缘检测的作用 边缘…

STM32 字符数组结束符 “\0”

STM32 字符数组结束符 “\0” 使用字符数组使用printf&#xff0c;string参考 使用字符数组 使用STM32的串口发送数据&#xff0c;核心代码如下&#xff1a; char str[] "hello world!\n\r";while(1) {HAL_UART_Transmit(&huart2, str, sizeof (str), 10);HAL…

【力扣刷题日记】1173.即时食物配送I

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1173.即时食物配送I 表&#xff1a;Delivery 列名类型delivery_idintcustomer_idintorder_datedatecustomer…

Java学生管理系统(附完整代码)两个版本

目录 学生管理系统 需求&#xff1a; 分析&#xff1a; 初始菜单&#xff1a; 学生类&#xff1a; 添加功能&#xff1a; 删除功能&#xff1a; 修改功能&#xff1a; 查询功能&#xff1a; 设计图 学生管理系统(基础版)独立开发 所用方法 代码: Student类: Stud…

洛谷 P2895 [USACO08FEB] Meteor Shower S

思路&#xff1a;BFS 这是一道BFS的题母庸质疑&#xff0c;其实质上是一个迷宫问题。但是&#xff0c;又与迷宫问题有不同的地方&#xff0c;因为这里有干扰因素&#xff0c;所以我们说这种问题就是有限制条件的迷宫问题。 BFS的照常遍历是没有问题。在题目中我们还需要考虑这…

LabVIEW双通道太阳射电频谱观测系统

LabVIEW双通道太阳射电频谱观测系统 开发了一个基于LabVIEW平台开发的双通道高速太阳射电频谱观测系统。该系统实时监测太阳射电爆发&#xff0c;具有随机性、持续时间短、变化快等特点。通过高速信号采集卡实现1.5 GS/s的信号采集&#xff0c;时间分辨率可达4ms&#xff0c;频…

类的新功能

类的新功能 默认成员函数 在C11之前&#xff0c;一个类中有如下六个默认成员函数&#xff1a; 构造函数。拷贝构造函数赋值重载析构函数取地址重载函数const取地址函数 其中前四个默认成员函数最重要&#xff0c;后面两个默认成员函数一般不会用到&#xff0c;这里默认成员…

c++的输入输出与判断

c是一门高级语言&#xff0c;从本篇起我将依次介绍c的各种知识。 在第一节课&#xff0c;我们要介绍c输入语句、输出语句、判断语句。 注明&#xff1a;在本篇中都使用下面的框架&#xff0c;在下一篇文章介绍本框架的原理。 #include<iostream> using namespace std;…

PHPCMS v9城市分站插件

PHPCMS自带的有多站点功能&#xff0c;但是用过的朋友都知道&#xff0c;自带的多站点功能有很多的不方便之处&#xff0c;例如站点栏目没法公用&#xff0c;每个站点都需要创建模型、每个站点都需要单独添加内容&#xff0c;还有站点必须静态化。如果你内容很多这些功能当然无…

虚函数和纯虚函数

虚函数 被virtual修饰的成员函数称为虚函数 定义一个函数为虚函数&#xff0c;是为了使用基类指针调用子类函数。虚函数&#xff0c;不代表函数不被实现。只有纯虚函数才不被实现&#xff0c;纯虚函数定义了一个接口&#xff0c;起到规范的作用。 #include <iostream>…

【AXIS】AXI-Stream FIFO设计实现(四)——异步时钟

前文介绍了几种同步时钟情况下的AXI Stream FIFO实现方式&#xff0c;一般来说&#xff0c;FIFO也需要承担异步时钟域模块间数据传输的功能&#xff0c;本文介绍异步AXIS FIFO的实现方式。 如前文所说&#xff0c;AXI-Stream FIFO十分类似于FWFT异步FIFO&#xff0c;推荐参考前…

B201-SpringBoot整合Shiro

目录 ShiroShiro核心组件SpringBoot整合Shiro1.创建新SpringBoot项目和导包2.自定义Shiro过滤器Realm3.配置类ShiroConfig编写认证和授权规则案例&#xff1a;案例思路改造ShiroConfigAccountController配置视图解析器templates下新建3个页面启动测试 登录认证设置自定义登录页…