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

本文详细介绍了C++标准库中的std::sort排序算法,包括其基本概念、语法、使用示例,以及与std::stable_sort的区别。此外,还展示了如何在自定义类型上应用std::sort进行排序。
摘要由CSDN通过智能技术生成

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; // 升序排序  
});
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值