#include <iostream>
#include <vector>
// write your code here......
#include<algorithm>

using namespace std;

int main() {

    int num;
    vector<int> v;
    for (int i = 0; i < 5; i++) {
        cin >> num;
        v.push_back(num);
    }
    //自定义降序
    sort(v.begin(),v.end(), [](int a, int b){return a > b;});
    for_each(v.begin(), v.end(), [](int num){
        cout<<num<<" ";
    });
    // write your code here......
    

    return 0;
}

STL 排序 & 遍历算法 超详细使用指南(全场景示例,零基础易懂)

STL(标准模板库)的排序算法(核心是 sort)和遍历算法(核心是 for_each)是C++开发中最常用的工具,结合容器(如vector/array/list)使用能极大简化代码。下面分「排序算法」和「遍历算法」两部分讲解,包含语法、示例、注意事项,所有代码可直接运行!

一、STL 排序算法(核心:sort

STL排序算法主要在 <algorithm> 头文件中(#include<algorithm>),其中 sort 是最常用的,另外补充 stable_sort(稳定排序)、list::sort(针对list容器)。

1. 核心特性

  • sort不稳定排序(相等元素的相对位置可能改变),时间复杂度 O(n log n),效率极高;
  • stable_sort稳定排序(相等元素相对位置不变),时间复杂度略高,适合需要保留相等元素顺序的场景;
  • 适用容器:sort 要求「随机访问迭代器」(vector/array/deque),list 不能用 std::sort,需用自身成员函数 list.sort()

2. 基础用法:默认升序排序

语法:sort(起始迭代器, 结束迭代器);

  • 起始迭代器:容器第一个元素的迭代器(如 v.begin());
  • 结束迭代器:容器尾后迭代器(如 v.end(),不指向任何元素,仅作为结束标志)。

示例(vector升序排序)

#include <iostream>
#include <vector>
#include <algorithm> // 排序算法必须包含此头文件
using namespace std;

int main() {
    vector<int> v = {5, 2, 9, 1, 5, 6};
    
    // 默认升序排序
    sort(v.begin(), v.end());
    
    // 遍历输出:1 2 5 5 6 9
    for (int num : v) {
        cout << num << " ";
    }
    return 0;
}

3. 自定义排序:降序/自定义规则

语法:sort(起始迭代器, 结束迭代器, 比较函数);比较函数可以是「lambda表达式(推荐)」「仿函数」「普通函数指针」,优先用lambda(简洁)。

示例1:降序排序(lambda)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v = {5, 2, 9, 1, 5, 6};
    
    // 自定义降序排序(lambda表达式)
    sort(v.begin(), v.end(), [](int a, int b) {
        return a > b; // a > b 时,a排在b前面 → 降序
    });
    
    // 遍历输出:9 6 5 5 2 1
    for (int num : v) {
        cout << num << " ";
    }
    return 0;
}

示例2:对自定义类型排序(比如结构体)

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

// 自定义结构体:学生(姓名+分数)
struct Student {
    string name;
    int score;
};

int main() {
    vector<Student> stu = {
        {"张三", 85},
        {"李四", 92},
        {"王五", 78}
    };
    
    // 按分数降序排序(分数高的在前)
    sort(stu.begin(), stu.end(), [](const Student& s1, const Student& s2) {
        return s1.score > s2.score;
    });
    
    // 遍历输出
    for (const auto& s : stu) {
        cout << s.name << ":" << s.score << endl;
    }
    return 0;
}

输出:

李四:92
张三:85
王五:78

4. 特殊容器:list的排序(不能用std::sort)

list 是双向链表,无随机访问迭代器,因此不能用 std::sort,需用自身成员函数 list.sort()

#include <iostream>
#include <list>
using namespace std;

int main() {
    list<int> l = {5, 2, 9, 1};
    
    // list自带排序:默认升序
    l.sort(); 
    // 降序排序:l.sort(greater<int>());
    
    // 遍历输出:1 2 5 9
    for (int num : l) {
        cout << num << " ";
    }
    return 0;
}

5. 稳定排序:stable_sort

当需要保留「相等元素的原始相对位置」时,用 stable_sort

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    // 元素是pair:(值, 原始索引),演示稳定排序
    vector<pair<int, int>> v = {{5,1}, {2,2}, {5,3}, {1,4}};
    
    // 按第一个值升序,稳定排序(两个5的相对位置不变)
    stable_sort(v.begin(), v.end(), [](const auto& a, const auto& b) {
        return a.first < b.first;
    });
    
    // 输出:(1,4) (2,2) (5,1) (5,3)
    for (auto& p : v) {
        cout << "(" << p.first << "," << p.second << ") ";
    }
    return 0;
}

二、STL 遍历算法(核心:for_each

STL遍历算法主要有 for_each<algorithm> 头文件),另外补充C++11的「范围for循环」(最简洁)、「迭代器遍历」(兼容所有版本)。

1. 核心:for_each 算法

语法:for_each(起始迭代器, 结束迭代器, 处理函数);

  • 处理函数:可以是普通函数「lambda表达式」「函数对象」,用于处理每个元素;
  • 优势:代码模块化,处理逻辑可复用。

示例1:用lambda遍历并修改元素

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4};
    
    // for_each遍历,每个元素+10(传引用修改原数据)
    for_each(v.begin(), v.end(), [](int& num) {
        num += 10;
        cout << num << " "; // 输出:11 12 13 14
    });
    return 0;
}

示例2:用普通函数处理遍历逻辑(复用场景)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 自定义处理函数:打印元素并计算总和(用全局变量/引用传值)
int sum = 0;
void printAndSum(int num) {
    cout << num << " ";
    sum += num;
}

int main() {
    vector<int> v = {1, 2, 3, 4};
    
    // 调用for_each,传入函数名
    for_each(v.begin(), v.end(), printAndSum);
    
    cout << "\n总和:" << sum << endl; // 输出:总和:10
    return 0;
}

2. 最简洁:范围for循环(C++11+,非算法但最常用)

语法:for(元素类型 变量 : 容器名) { 处理逻辑 }

  • 优点:代码量最少、最易懂,日常开发99%场景用这个;
  • & 可修改原元素,加 const & 只读(无拷贝开销)。

示例(只读遍历 + 修改遍历)

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4};
    
    // 1. 只读遍历(const & 最优写法,无拷贝+安全)
    cout << "原始数据:";
    for (const auto& num : v) {
        cout << num << " "; // 输出:1 2 3 4
    }
    
    // 2. 修改遍历(加&引用)
    for (auto& num : v) {
        num *= 2; // 每个元素×2
    }
    
    // 3. 再次遍历输出
    cout << "\n修改后:";
    for (const auto& num : v) {
        cout << num << " "; // 输出:2 4 6 8
    }
    return 0;
}

3. 兼容所有版本:迭代器遍历

语法:用容器的迭代器(iterator/const_iterator)从 begin() 遍历到 end()

  • 适合:老旧编译器(C++11之前)、需要手动控制遍历步长的场景。

示例(正向/反向迭代器)

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4};
    
    // 1. 正向迭代器(可读可写)
    cout << "正向遍历:";
    for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
        cout << *it << " "; // *it 解引用获取元素
    }
    
    // 2. 反向迭代器(从后往前)
    cout << "\n反向遍历:";
    for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
        cout << *it << " "; // 输出:4 3 2 1
    }
    
    // 3. 常量迭代器(只读,不可修改)
    cout << "\n常量遍历:";
    for (vector<int>::const_iterator it = v.cbegin(); it != v.cend(); ++it) {
        cout << *it << " ";
    }
    return 0;
}

4. 遍历算法对比:for_each vs 范围for

for_each

逻辑可复用、模块化

语法略长

处理逻辑需要复用的场景

范围for

最简洁、易读、效率高

依赖C++11+

日常遍历(99%场景)

迭代器遍历

兼容所有C++版本、可控步长

代码最长、易写错

老旧编译器、特殊遍历需求

三、综合示例:排序 + 遍历

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    // 1. 初始化容器
    vector<int> v = {9, 3, 7, 1, 5};
    
    // 2. 排序:降序
    sort(v.begin(), v.end(), [](int a, int b) {
        return a > b;
    });
    
    // 3. 遍历:用for_each打印,同时计算总和
    int sum = 0;
    cout << "降序结果:";
    for_each(v.begin(), v.end(), [&sum](int num) {
        cout << num << " ";
        sum += num;
    });
    
    // 4. 输出总和
    cout << "\n总和:" << sum << endl; // 总和:25
    return 0;
}

输出:

降序结果:9 7 5 3 1 
总和:25

四、核心注意事项(避坑)

  1. 排序算法迭代器要求std::sort 仅支持随机访问迭代器(vector/array/deque),list/set(set本身有序)不用;
  2. 遍历修改元素必须加&:不管是范围for还是for_each,修改元素时必须传引用(int&/auto&),否则只修改副本;
  3. const_iterator不可修改:常量迭代器(cbegin()/cend())只能读,不能修改元素;
  4. sort默认升序:底层是less<T>(),降序用greater<T>()或自定义lambda;
  5. for_each不返回值:如需返回处理结果,可通过引用/全局变量传递(如示例中的总和)。

总结

  • 排序:优先用 sort(默认升序,lambda自定义规则),list用list.sort(),稳定排序用stable_sort
  • 遍历:日常优先用「范围for循环」(for(const auto& x : v)),需要复用逻辑用for_each,老旧编译器用迭代器;
  • 核心原则:简洁优先,效率其次(STL算法效率已足够高,优先保证代码易读)。

掌握这两套算法,能覆盖99%的排序/遍历场景,是C++ STL的核心基础!