目 录CONTENT

文章目录

C++ STL:算法-排序算法

TalentQ
2025-09-02 / 0 评论 / 0 点赞 / 10 阅读 / 0 字

引言

排序是编程中最常见的数据处理操作之一。C++ STL(标准模板库)为我们提供了多种高效且灵活的排序相关算法。本文将详细介绍 STL 排序算法,包括 sortstable_sortpartial_sortpartial_sort_copynth_elementis_sortedis_sorted_until

1 std::sort —— 高效的通用排序算法

原理

std::sort 是 STL 中最常用的排序算法,采用混合排序(IntroSort),结合了快速排序、堆排序和插入排序的优点。它在平均情况下表现优异,最坏情况下也能保证较好的性能。

用法

#include <algorithm>
#include <vector>
#include <iostream>

// 按 Google 风格注释
int main() {
  // 初始化一个整数向量
  std::vector<int> vec = {5, 2, 9, 1, 5, 6};

  // 对整个向量进行升序排序
  std::sort(vec.begin(), vec.end());

  // 输出排序结果
  for (int num : vec) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  // 使用自定义比较器实现降序排序
  std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });

  for (int num : vec) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  return 0;
}

场景

  • 需要对整个容器进行排序

  • 不关心元素间的原始顺序(非稳定排序)

  • 追求最快速度

性能

  • 时间复杂度:O(nlog⁡n)

  • 空间复杂度:O(log⁡n)

2 std::stable_sort —— 保持相等元素顺序的排序

原理

std::stable_sort 保证相等元素的原始顺序不变,底层实现通常为归并排序,最坏情况下时间复杂度也为 O(nlog⁡n)。

用法

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

struct Person {
  std::string name;
  int age;
};

// Google 风格注释
int main() {
  // 初始化人员列表
  std::vector<Person> people = {
      {"Alice", 30}, {"Bob", 25}, {"Charlie", 25}, {"David", 35}
  };

  // 按年龄排序,保持原始顺序
  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.name << " " << person.age << std::endl;
  }

  return 0;
}

场景

  • 需要保持相等元素原始顺序(如多字段排序)

  • 稳定性优先于速度

性能

  • 时间复杂度:O(nlog⁡n)

  • 空间复杂度:O(n)(可能需要额外空间)

3 std::partial_sort —— 局部排序,适合 Top-K 问题

原理

std::partial_sort 只对前 k 个元素进行排序,剩余元素无序。底层通常采用堆排序。

用法

#include <algorithm>
#include <vector>
#include <iostream>

// Google 风格注释
int main() {
  // 初始化向量
  std::vector<int> vec = {10, 3, 5, 8, 2, 7};

  // 只排序前 3 个元素,剩下的无序
  std::partial_sort(vec.begin(), vec.begin() + 3, vec.end());

  // 输出前 3 个最小值
  for (int i = 0; i < 3; ++i) {
    std::cout << vec[i] << " ";
  }
  std::cout << std::endl;

  return 0;
}

场景

  • 只关心前k个最小/最大元素(如 Top-K)

  • 比完全排序更高效

性能

  • 时间复杂度:O(n+klog⁡k)

4 std::partial_sort_copy —— 局部排序并拷贝到新容器

原理

std::partial_sort_copy 将输入区间的前 k 个最小(或最大)元素排序后拷贝到目标区间,源容器不变。

用法

#include <algorithm>
#include <vector>
#include <iostream>

// Google 风格注释
int main() {
  std::vector<int> src = {7, 2, 5, 9, 1, 4};
  std::vector<int> dst(3);

  // 拷贝并排序 src 的前 3 个最小值到 dst
  std::partial_sort_copy(src.begin(), src.end(), dst.begin(), dst.end());

  for (int num : dst) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  return 0;
}

场景

  • 只需要部分排序结果,且不希望修改原容器

  • Top-K 结果拷贝到新容器

性能

  • 时间复杂度:O(n+klog⁡k)

5 std::nth_element —— 找到第 n 小(大)元素

原理

std::nth_element 是快速选择算法的实现。它调整容器,使第 n 个位置上的元素正好是排序后该位置的元素,左侧元素都不大于它,右侧都不小于它,但左右两侧无序。

用法

#include <algorithm>
#include <vector>
#include <iostream>

// Google 风格注释
int main() {
  std::vector<int> vec = {6, 2, 9, 1, 7, 5};

  // 找到第 3 小元素(索引 2),并调整位置
  std::nth_element(vec.begin(), vec.begin() + 2, vec.end());

  std::cout << "第3小元素: " << vec[2] << std::endl;

  // 输出前3个元素(不保证有序,但都 <= vec[2])
  for (int i = 0; i <= 2; ++i) {
    std::cout << vec[i] << " ";
  }
  std::cout << std::endl;

  return 0;
}

场景

  • 只关心第n小/大元素

  • 快速求中位数、分位数

  • Top-K 无序结果

性能

  • 平均时间复杂度:O(n)

6 std::is_sortedstd::is_sorted_until —— 判断是否有序

原理

  • std::is_sorted 检查整个区间是否有序。

  • std::is_sorted_until 返回第一个无序元素的迭代器。

用法

#include <algorithm>
#include <vector>
#include <iostream>

// Google 风格注释
int main() {
  std::vector<int> vec = {1, 2, 3, 5, 4, 6};

  // 判断是否完全有序
  if (std::is_sorted(vec.begin(), vec.end())) {
    std::cout << "向量已排序" << std::endl;
  } else {
    std::cout << "向量未排序" << std::endl;
  }

  // 找到第一个无序位置
  auto it = std::is_sorted_until(vec.begin(), vec.end());
  std::cout << "第一个无序元素: " << *it << std::endl;

  return 0;
}

场景

  • 判断容器是否已排序

  • 快速定位无序区间

7 对比与扩展

传统排序方法

  • 冒泡排序、选择排序、插入排序等:实现简单,但性能远不如 STL 算法。

  • STL 排序算法都经过高度优化,推荐优先使用。

STL 排序算法选择建议

算法

是否稳定

适用场景

时间复杂度

sort

全排序,速度优先

O(nlog⁡n)

stable_sort

全排序,需稳定性

O(nlog⁡n)

partial_sort

Top-K,部分排序

O(n+klog⁡k)

partial_sort_copy

Top-K,拷贝到新容器

O(n+klog⁡k)

nth_element

第 n 小/大,分位数

O(n)

is_sorted

N/A

判断是否有序

O(n)

is_sorted_until

N/A

找无序点

O(n)

0

评论区