C++ 排序算法完全指南:从入门到实践

C++ 排序算法完全指南:从入门到实践

🌟 一、排序基础认知

排序的本质:把一群数据按照特定规则重新排列(比如从矮到高排队)
核心目标:让数据变得有序,方便后续快速查找和处理
关键指标

  • 🚀 速度:处理百万数据要快(时间复杂度)
  • 🏠 内存:尽量少占内存(空间复杂度)
  • 🤝 稳定性:相同元素保持原顺序(重要吗?看需求!)

二、常用排序方法详解

1️⃣ 标准库一键排序(推荐首选)

适用场景:日常开发中90%的情况
优点:简单高效,底层优化好

#include <algorithm>
#include <vector>

int main() {
    std::vector<int> nums = {5, 3, 7, 1, 9};
    
    // 默认升序(从小到大)
    std::sort(nums.begin(), nums.end()); 
    
    // 降序排列(从大到小)
    std::sort(nums.begin(), nums.end(), std::greater<int>());
    
    return 0;
}

📝 注意点

  • 适用于数组/vector等连续容器
  • 对链表无效(链表要用list.sort())
  • 默认不保持相同元素的原始顺序

2️⃣ 自定义排序规则

适用场景:需要特殊排序逻辑
示例需求:按绝对值排序、按学生成绩排序等

// 按字符串长度排序
std::vector<std::string> words = {"apple", "cat", "banana"};
std::sort(words.begin(), words.end(), [](const auto& a, const auto& b) {
    return a.size() < b.size(); 
});
// 结果:cat → apple → banana

💡 经典案例:多条件排序

struct Student {
    std::string name;
    int score;
    int age;
};

std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
    // 先按成绩降序,成绩相同按年龄升序
    if (a.score != b.score) 
        return a.score > b.score;
    else 
        return a.age < b.age;
});

3️⃣ 结构体/对象排序

两种方式

  1. 重载运算符(适合固定排序规则)
struct Book {
    std::string title;
    double price;
    
    // 按价格升序
    bool operator<(const Book& other) const {
        return price < other.price;
    }
};
  1. 自定义比较函数(灵活多变)
std::sort(books.begin(), books.end(), [](const Book& a, const Book& b) {
    return a.title < b.title; // 按书名排序
});

4️⃣ 稳定排序(保持原顺序)

适用场景:需要多次排序时保留前次顺序

std::vector<std::pair<int, std::string>> records = {
    {90, "张三"}, {85, "李四"}, {90, "王五"}
};

// 按分数排序,相同分数保持录入顺序
std::stable_sort(records.begin(), records.end(), 
    [](const auto& a, const auto& b) {
        return a.first > b.first;
    });
/* 结果:
   90 张三 → 90 王五 → 85 李四
   保持相同分数的原始录入顺序 */

5️⃣ 部分排序(Top K问题)

适用场景:找前N名/省时省内存

std::vector<int> scores = {78, 92, 65, 88, 95, 81};
int k = 3; // 找前三名

// 只排前3个元素,其他不管
std::partial_sort(scores.begin(), scores.begin()+k, scores.end(), 
                 std::greater<int>());
// 结果:95 92 88 65 78 81

6️⃣ 堆排序(优先队列)

适用场景:实时获取最大值/最小值

#include <queue>

// 小顶堆(总弹出最小值)
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;

// 大顶堆(默认,总弹出最大值)
std::priority_queue<int> max_heap;

// 示例:实时获取最新三个最高分
std::vector<int> scores = {85, 92, 78, 95, 88};
for (int score : scores) {
    max_heap.push(score);
    if (max_heap.size() > 3) 
        max_heap.pop();
}
// 最终堆中保留:95, 92, 88

7️⃣ 快速排序(手写实现)

核心思想:分而治之 + 基准值
实现步骤

  1. 选基准(如中间值)
  2. 分区:小的放左边,大的放右边
  3. 递归处理左右子数组
void quickSort(int arr[], int left, int right) {
    if (left >= right) return;
    
    int pivot = arr[(left+right)/2]; // 基准值
    int i = left, j = right;
    
    while (i <= j) {
        while (arr[i] < pivot) i++; // 找左边大的
        while (arr[j] > pivot) j--; // 找右边小的
        if (i <= j) {
            std::swap(arr[i], arr[j]);
            i++; j--;
        }
    }
    
    quickSort(arr, left, j);  // 排左边
    quickSort(arr, i, right); // 排右边
}

三、基础排序算法(理解原理)

1️⃣ 选择排序

工作原理:每轮选最小/最大放前面
类比:打牌时每次挑最小的牌排列

void selectionSort(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        int min_idx = i;
        for (int j = i+1; j < n; j++) {
            if (arr[j] < arr[min_idx]) 
                min_idx = j;
        }
        std::swap(arr[i], arr[min_idx]);
    }
}

2️⃣ 冒泡排序

工作原理:相邻元素比较交换,像气泡上浮
优化点:添加标记提前终止

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        bool swapped = false;
        for (int j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                std::swap(arr[j], arr[j+1]);
                swapped = true;
            }
        }
        if (!swapped) break; // 已有序则提前退出
    }
}

3️⃣ 插入排序

工作原理:像整理扑克牌,逐个插入合适位置
优势:对基本有序数据效率极高

void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i-1;
        while (j >= 0 && arr[j] > key) {
            arr[j+1] = arr[j]; // 后移元素
            j--;
        }
        arr[j+1] = key; // 插入正确位置
    }
}

四、排序算法对比表

算法平均时间复杂度最坏情况内存消耗稳定性适用场景
std::sortO(n log n)O(n²)O(log n)不稳定通用场景
快速排序O(n log n)O(n²)O(log n)不稳定内存排序
归并排序O(n log n)O(n log n)O(n)稳定大数据/稳定需求
堆排序O(n log n)O(n log n)O(1)不稳定Top K问题
插入排序O(n²)O(n²)O(1)稳定小数据/基本有序
冒泡排序O(n²)O(n²)O(1)稳定教学示例
选择排序O(n²)O(n²)O(1)不稳定教学示例

五、选择排序算法的黄金法则

  1. 默认选择:优先使用std::sort,经过高度优化
  2. 需要稳定:选stable_sort或归并排序
  3. 海量数据:考虑分治策略或外部排序
  4. 实时处理:使用堆排序维护Top N
  5. 小数据量(<100):插入排序更高效
  6. 链表排序:使用list.sort()(归并实现)
  7. 并行处理:C++17起可用std::execution::par并行加速

六、性能优化技巧

  1. 减少拷贝:对大型对象使用指针或移动语义
  2. 预先分配内存:避免排序过程中的内存分配
  3. 使用视图:排序时只处理索引,不移动实际数据
  4. 避免虚函数:比较函数尽量简单高效
  5. 利用缓存:让相关数据在内存中连续存储

七、常见问题解答

Q:已经排序好的数据用什么算法最快?
A:插入排序,时间复杂度可达O(n)

Q:1亿个数据选哪种排序?
A:先用std::sort,如果内存不足考虑分块排序+归并

Q:如何判断排序是否稳定?
A:看相同元素顺序是否改变,例如:

struct Item { int id; int value; };
std::vector<Item> items = {{1,5}, {2,5}, {3,5}};
// 稳定排序后id顺序保持1→2→3

八、实战练习建议

  1. 尝试手写不同排序算法
  2. 用大量随机数据测试各算法性能
  3. 实现多条件组合排序(如先按年龄再按分数)
  4. 处理自定义对象的排序
  5. 解决LeetCode排序相关题目(如#56合并区间)

掌握这些排序技巧,你就能轻松应对各种数据排列需求! 🚀
求三连~🐍🐍🐍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值