Skip to content

C++ STL 算法

概述

STL算法库提供了丰富的通用算法,这些算法可以作用于不同的容器和数据结构。算法通过迭代器与容器解耦,实现了高度的可重用性。本章介绍查找、排序、修改、数值算法等常用STL算法。

🔍 查找算法

基础查找

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

class SearchAlgorithms {
public:
    static void basicSearch() {
        std::cout << "=== 基础查找算法 ===" << std::endl;
        
        std::vector<int> vec{1, 3, 5, 7, 9, 11, 13, 15};
        
        // find - 查找元素
        auto it = std::find(vec.begin(), vec.end(), 7);
        if (it != vec.end()) {
            std::cout << "找到7,位置: " << std::distance(vec.begin(), it) << std::endl;
        }
        
        // find_if - 条件查找
        auto it2 = std::find_if(vec.begin(), vec.end(), [](int x) {
            return x > 10;
        });
        if (it2 != vec.end()) {
            std::cout << "第一个大于10的数: " << *it2 << std::endl;
        }
        
        // count - 计数
        std::vector<int> vec2{1, 2, 3, 2, 4, 2, 5};
        int count = std::count(vec2.begin(), vec2.end(), 2);
        std::cout << "数字2出现次数: " << count << std::endl;
        
        // count_if - 条件计数
        int even_count = std::count_if(vec2.begin(), vec2.end(), [](int x) {
            return x % 2 == 0;
        });
        std::cout << "偶数个数: " << even_count << std::endl;
    }
    
    static void binarySearch() {
        std::cout << "\n=== 二分查找算法 ===" << std::endl;
        
        std::vector<int> sorted_vec{1, 3, 5, 7, 9, 11, 13, 15};
        
        // binary_search - 二分查找存在性
        bool found = std::binary_search(sorted_vec.begin(), sorted_vec.end(), 7);
        std::cout << "7是否存在: " << (found ? "是" : "否") << std::endl;
        
        // lower_bound - 查找第一个不小于目标的元素
        auto lb = std::lower_bound(sorted_vec.begin(), sorted_vec.end(), 7);
        std::cout << "lower_bound(7): " << *lb << std::endl;
        
        // upper_bound - 查找第一个大于目标的元素
        auto ub = std::upper_bound(sorted_vec.begin(), sorted_vec.end(), 7);
        std::cout << "upper_bound(7): " << *ub << std::endl;
        
        // equal_range - 获取相等元素的范围
        auto range = std::equal_range(sorted_vec.begin(), sorted_vec.end(), 7);
        std::cout << "equal_range(7): [" << *range.first << ", " << *range.second << ")" << std::endl;
    }
    
    static void searchPatterns() {
        std::cout << "\n=== 模式查找 ===" << std::endl;
        
        std::vector<int> haystack{1, 2, 3, 4, 5, 6, 7, 8, 9};
        std::vector<int> needle{4, 5, 6};
        
        // search - 查找子序列
        auto it = std::search(haystack.begin(), haystack.end(), 
                             needle.begin(), needle.end());
        if (it != haystack.end()) {
            std::cout << "找到子序列,起始位置: " << std::distance(haystack.begin(), it) << std::endl;
        }
        
        // search_n - 查找连续n个相同元素
        std::vector<int> vec{1, 1, 2, 2, 2, 3, 3};
        auto it2 = std::search_n(vec.begin(), vec.end(), 3, 2);
        if (it2 != vec.end()) {
            std::cout << "找到连续3个2,起始位置: " << std::distance(vec.begin(), it2) << std::endl;
        }
        
        // adjacent_find - 查找相邻重复元素
        auto it3 = std::adjacent_find(vec.begin(), vec.end());
        if (it3 != vec.end()) {
            std::cout << "第一个重复元素: " << *it3 << std::endl;
        }
    }
};

int main() {
    SearchAlgorithms::basicSearch();
    SearchAlgorithms::binarySearch();
    SearchAlgorithms::searchPatterns();
    
    return 0;
}

🔄 排序算法

排序和分区

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <chrono>

class SortingAlgorithms {
public:
    static void basicSorting() {
        std::cout << "=== 基础排序算法 ===" << std::endl;
        
        std::vector<int> vec{64, 34, 25, 12, 22, 11, 90};
        
        std::cout << "原始数据: ";
        printVector(vec);
        
        // sort - 快速排序
        std::vector<int> vec1 = vec;
        std::sort(vec1.begin(), vec1.end());
        std::cout << "sort结果: ";
        printVector(vec1);
        
        // stable_sort - 稳定排序
        std::vector<std::pair<int, char>> pairs{
            {3, 'a'}, {1, 'b'}, {3, 'c'}, {2, 'd'}
        };
        
        std::stable_sort(pairs.begin(), pairs.end(), 
            [](const auto& a, const auto& b) {
                return a.first < b.first;
            });
        
        std::cout << "stable_sort结果: ";
        for (const auto& p : pairs) {
            std::cout << "(" << p.first << "," << p.second << ") ";
        }
        std::cout << std::endl;
        
        // partial_sort - 部分排序
        std::vector<int> vec2 = vec;
        std::partial_sort(vec2.begin(), vec2.begin() + 3, vec2.end());
        std::cout << "partial_sort前3个: ";
        printVector(vec2);
    }
    
    static void customSorting() {
        std::cout << "\n=== 自定义排序 ===" << std::endl;
        
        struct Student {
            std::string name;
            int age;
            double gpa;
        };
        
        std::vector<Student> students{
            {"Alice", 20, 3.8},
            {"Bob", 19, 3.9},
            {"Charlie", 21, 3.7},
            {"David", 20, 3.85}
        };
        
        // 按年龄排序
        std::sort(students.begin(), students.end(), 
            [](const Student& a, const Student& b) {
                return a.age < b.age;
            });
        
        std::cout << "按年龄排序:" << std::endl;
        for (const auto& s : students) {
            std::cout << s.name << " (" << s.age << ") ";
        }
        std::cout << std::endl;
        
        // 多条件排序
        std::sort(students.begin(), students.end(), 
            [](const Student& a, const Student& b) {
                if (a.age != b.age) return a.age < b.age;
                return a.gpa > b.gpa;  // 年龄相同时按GPA降序
            });
        
        std::cout << "多条件排序:" << std::endl;
        for (const auto& s : students) {
            std::cout << s.name << " (" << s.age << ", " << s.gpa << ") ";
        }
        std::cout << std::endl;
    }
    
    static void partitioning() {
        std::cout << "\n=== 分区算法 ===" << std::endl;
        
        std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        
        // partition - 分区
        auto pivot = std::partition(vec.begin(), vec.end(), [](int x) {
            return x % 2 == 0;  // 偶数在前
        });
        
        std::cout << "partition结果: ";
        printVector(vec);
        std::cout << "分界点: " << std::distance(vec.begin(), pivot) << std::endl;
        
        // stable_partition - 稳定分区
        std::vector<int> vec2{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        auto pivot2 = std::stable_partition(vec2.begin(), vec2.end(), [](int x) {
            return x % 2 == 0;
        });
        
        std::cout << "stable_partition结果: ";
        printVector(vec2);
        
        // nth_element - 第n个元素
        std::vector<int> vec3{64, 34, 25, 12, 22, 11, 90};
        std::nth_element(vec3.begin(), vec3.begin() + 3, vec3.end());
        std::cout << "第4小的元素: " << vec3[3] << std::endl;
    }
    
private:
    static void printVector(const std::vector<int>& vec) {
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
};

🔧 修改算法

变换和生成

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>

class ModifyingAlgorithms {
public:
    static void transformation() {
        std::cout << "=== 变换算法 ===" << std::endl;
        
        std::vector<int> src{1, 2, 3, 4, 5};
        std::vector<int> dest(src.size());
        
        // transform - 变换
        std::transform(src.begin(), src.end(), dest.begin(), [](int x) {
            return x * x;
        });
        
        std::cout << "平方变换: ";
        for (int n : dest) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // transform 二元操作
        std::vector<int> src2{10, 20, 30, 40, 50};
        std::transform(src.begin(), src.end(), src2.begin(), dest.begin(), 
            [](int a, int b) {
                return a + b;
            });
        
        std::cout << "加法变换: ";
        for (int n : dest) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
    
    static void copying() {
        std::cout << "\n=== 复制算法 ===" << std::endl;
        
        std::vector<int> src{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        std::vector<int> dest;
        
        // copy_if - 条件复制
        std::copy_if(src.begin(), src.end(), std::back_inserter(dest), [](int x) {
            return x % 2 == 0;
        });
        
        std::cout << "偶数复制: ";
        for (int n : dest) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // unique_copy - 去重复制
        std::vector<int> src2{1, 1, 2, 2, 2, 3, 3, 4, 5, 5};
        std::vector<int> unique_dest;
        
        std::unique_copy(src2.begin(), src2.end(), std::back_inserter(unique_dest));
        
        std::cout << "去重复制: ";
        for (int n : unique_dest) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
    
    static void generation() {
        std::cout << "\n=== 生成算法 ===" << std::endl;
        
        // fill - 填充
        std::vector<int> vec(10);
        std::fill(vec.begin(), vec.end(), 42);
        
        std::cout << "fill填充: ";
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // generate - 生成
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(1, 100);
        
        std::generate(vec.begin(), vec.end(), [&]() {
            return dis(gen);
        });
        
        std::cout << "generate生成: ";
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // iota - 递增序列
        std::vector<int> seq(10);
        std::iota(seq.begin(), seq.end(), 1);
        
        std::cout << "iota序列: ";
        for (int n : seq) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
    
    static void removal() {
        std::cout << "\n=== 删除算法 ===" << std::endl;
        
        std::vector<int> vec{1, 2, 3, 2, 4, 2, 5};
        
        std::cout << "原始: ";
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // remove - 移除元素
        auto new_end = std::remove(vec.begin(), vec.end(), 2);
        vec.erase(new_end, vec.end());
        
        std::cout << "移除2后: ";
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // remove_if - 条件移除
        std::vector<int> vec2{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        auto new_end2 = std::remove_if(vec2.begin(), vec2.end(), [](int x) {
            return x % 2 == 0;
        });
        vec2.erase(new_end2, vec2.end());
        
        std::cout << "移除偶数后: ";
        for (int n : vec2) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
};

🔢 数值算法

累积和数值操作

cpp
#include <iostream>
#include <vector>
#include <numeric>
#include <functional>

class NumericAlgorithms {
public:
    static void accumulation() {
        std::cout << "=== 累积算法 ===" << std::endl;
        
        std::vector<int> vec{1, 2, 3, 4, 5};
        
        // accumulate - 累积
        int sum = std::accumulate(vec.begin(), vec.end(), 0);
        std::cout << "累加和: " << sum << std::endl;
        
        // 自定义操作
        int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>());
        std::cout << "累积: " << product << std::endl;
        
        // 字符串连接
        std::vector<std::string> words{"Hello", " ", "World", "!"};
        std::string sentence = std::accumulate(words.begin(), words.end(), std::string(""));
        std::cout << "字符串连接: " << sentence << std::endl;
        
        // reduce (C++17) - 并行累积
        #ifdef __cpp_lib_parallel_algorithm
        int parallel_sum = std::reduce(vec.begin(), vec.end(), 0);
        std::cout << "并行累积: " << parallel_sum << std::endl;
        #endif
    }
    
    static void partialSums() {
        std::cout << "\n=== 部分和算法 ===" << std::endl;
        
        std::vector<int> vec{1, 2, 3, 4, 5};
        std::vector<int> result(vec.size());
        
        // partial_sum - 部分和
        std::partial_sum(vec.begin(), vec.end(), result.begin());
        
        std::cout << "原始: ";
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        std::cout << "部分和: ";
        for (int n : result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 自定义操作的部分和
        std::partial_sum(vec.begin(), vec.end(), result.begin(), std::multiplies<int>());
        
        std::cout << "部分积: ";
        for (int n : result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // adjacent_difference - 相邻差
        std::vector<int> diff_result(vec.size());
        std::adjacent_difference(vec.begin(), vec.end(), diff_result.begin());
        
        std::cout << "相邻差: ";
        for (int n : diff_result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
    
    static void innerProduct() {
        std::cout << "\n=== 内积算法 ===" << std::endl;
        
        std::vector<int> vec1{1, 2, 3, 4, 5};
        std::vector<int> vec2{2, 3, 4, 5, 6};
        
        // inner_product - 内积
        int dot_product = std::inner_product(vec1.begin(), vec1.end(), vec2.begin(), 0);
        std::cout << "内积: " << dot_product << std::endl;
        
        // 自定义操作
        int custom = std::inner_product(vec1.begin(), vec1.end(), vec2.begin(), 0,
            std::plus<int>(), [](int a, int b) {
                return a * b * 2;  // 每个乘积再乘以2
            });
        std::cout << "自定义内积: " << custom << std::endl;
    }
    
    static void gcdLcm() {
        std::cout << "\n=== 最大公约数和最小公倍数 ===" << std::endl;
        
        // gcd, lcm (C++17)
        #ifdef __cpp_lib_gcd_lcm
        int a = 48, b = 18;
        std::cout << "gcd(" << a << ", " << b << ") = " << std::gcd(a, b) << std::endl;
        std::cout << "lcm(" << a << ", " << b << ") = " << std::lcm(a, b) << std::endl;
        #endif
    }
};

🔀 排列和集合算法

排列组合

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

class PermutationAlgorithms {
public:
    static void permutations() {
        std::cout << "=== 排列算法 ===" << std::endl;
        
        std::vector<int> vec{1, 2, 3};
        
        std::cout << "所有排列:" << std::endl;
        do {
            for (int n : vec) {
                std::cout << n << " ";
            }
            std::cout << std::endl;
        } while (std::next_permutation(vec.begin(), vec.end()));
        
        // 重置到最小排列
        std::sort(vec.begin(), vec.end());
        
        std::cout << "\n逆序排列:" << std::endl;
        do {
            for (int n : vec) {
                std::cout << n << " ";
            }
            std::cout << std::endl;
        } while (std::prev_permutation(vec.begin(), vec.end()));
    }
    
    static void setOperations() {
        std::cout << "\n=== 集合算法 ===" << std::endl;
        
        std::vector<int> set1{1, 2, 3, 4, 5};
        std::vector<int> set2{3, 4, 5, 6, 7};
        std::vector<int> result;
        
        // set_union - 并集
        std::set_union(set1.begin(), set1.end(), 
                      set2.begin(), set2.end(), 
                      std::back_inserter(result));
        
        std::cout << "并集: ";
        for (int n : result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // set_intersection - 交集
        result.clear();
        std::set_intersection(set1.begin(), set1.end(), 
                             set2.begin(), set2.end(), 
                             std::back_inserter(result));
        
        std::cout << "交集: ";
        for (int n : result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // set_difference - 差集
        result.clear();
        std::set_difference(set1.begin(), set1.end(), 
                           set2.begin(), set2.end(), 
                           std::back_inserter(result));
        
        std::cout << "差集: ";
        for (int n : result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // set_symmetric_difference - 对称差集
        result.clear();
        std::set_symmetric_difference(set1.begin(), set1.end(), 
                                     set2.begin(), set2.end(), 
                                     std::back_inserter(result));
        
        std::cout << "对称差集: ";
        for (int n : result) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    SearchAlgorithms::basicSearch();
    SearchAlgorithms::binarySearch();
    SearchAlgorithms::searchPatterns();
    
    SortingAlgorithms::basicSorting();
    SortingAlgorithms::customSorting();
    SortingAlgorithms::partitioning();
    
    ModifyingAlgorithms::transformation();
    ModifyingAlgorithms::copying();
    ModifyingAlgorithms::generation();
    ModifyingAlgorithms::removal();
    
    NumericAlgorithms::accumulation();
    NumericAlgorithms::partialSums();
    NumericAlgorithms::innerProduct();
    NumericAlgorithms::gcdLcm();
    
    PermutationAlgorithms::permutations();
    PermutationAlgorithms::setOperations();
    
    return 0;
}

总结

STL算法库提供了丰富的通用算法,显著提高了开发效率:

算法分类

  • 查找算法: find, search, binary_search
  • 排序算法: sort, stable_sort, partial_sort
  • 修改算法: transform, copy, remove
  • 数值算法: accumulate, partial_sum, inner_product
  • 排列算法: next_permutation, set operations

性能特点

算法类型时间复杂度适用场景
线性查找O(n)无序数据
二分查找O(log n)有序数据
排序O(n log n)数据整理
线性变换O(n)数据处理

设计原则

  • 迭代器抽象: 算法与容器解耦
  • 函数对象: 自定义操作逻辑
  • 策略模式: 算法行为可配置
  • 泛型编程: 类型无关实现

最佳实践

  • 选择合适的算法复杂度
  • 利用STL避免重复造轮子
  • 结合lambda表达式简化代码
  • 注意算法的前置条件
  • 使用范围算法(C++20)

STL算法是C++高效编程的重要工具,掌握它们能大幅提升代码质量和开发速度。

本站内容仅供学习和研究使用。