稳定排序和非稳定排序

稳定排序(Stable Sort) 是指在排序过程中,相等元素的相对顺序保持不变的排序算法。换句话说,如果原始序列中有两个元素 AB 满足 A == B,且 A 原本在 B 之前,那么在排序后的序列中,A 仍然会在 B 之前。


稳定排序的核心特点

  1. 相等元素的顺序不变

    • 例如,原始序列:[ (Alice, 25), (Bob, 20), (Charlie, 25) ](按姓名和年龄存储)。
    • 如果先按年龄升序排序,再按姓名升序稳定排序,结果会是:
      [ (Bob, 20), (Alice, 25), (Charlie, 25) ]
      
      • 年龄相同的 AliceCharlie 的相对顺序与原始序列一致(Alice 在前)。
  2. 非稳定排序可能改变顺序

    • 如果使用非稳定排序(如 std::sort),年龄相同的 AliceCharlie 的顺序可能被交换:
      [ (Bob, 20), (Charlie, 25), (Alice, 25) ]
      

为什么需要稳定排序?

稳定排序在以下场景中非常重要:

  1. 多关键字排序

    • 例如,先按“部门”排序,再按“工资”稳定排序。这样能保证同一部门的员工按工资排序后,原始顺序(如入职时间)不会被破坏。
    • 示例:
      struct Employee {
          std::string dept;
          int salary;
          int id; // 入职编号
      };
      
      std::vector<Employee> employees = {
          {"HR", 5000, 101},
          {"IT", 7000, 201},
          {"HR", 6000, 102},
          {"IT", 6000, 202}
      };
      
      // 先按部门升序,再按工资升序(稳定排序保证同部门同工资的顺序不变)
      std::stable_sort(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) {
          return a.dept < b.dept; // 先按部门排序
      });
      std::stable_sort(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) {
          return a.salary < b.salary; // 再按工资稳定排序
      });
      
      // 结果:
      // [ ("HR", 5000, 101), ("HR", 6000, 102), ("IT", 6000, 202), ("IT", 7000, 201) ]
      // 注意:同部门同工资的顺序(如 HR 的 101 和 102)保持不变。
      
  2. 保留原始顺序的场景

    • 例如,对日志按时间戳排序,但希望相同时间戳的日志按原始输入顺序输出。

稳定排序 vs 非稳定排序

特性稳定排序非稳定排序
相等元素顺序保持不变可能改变
典型算法归并排序、插入排序、冒泡排序快速排序、堆排序、选择排序
STL 实现std::stable_sortstd::sort
时间复杂度通常 O(N log N)(归并排序)平均 O(N log N),最坏 O(N²)
空间复杂度可能需要额外空间(如归并排序)通常原地排序(如快速排序)

STL 中的稳定排序

在 C++ STL 中,std::stable_sort 是稳定排序的实现,而 std::sort 是非稳定的。
示例对比

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

struct Item {
    int value;
    int id; // 原始顺序标识
};

int main() {
    std::vector<Item> items = {
        {3, 1}, {1, 2}, {2, 3}, {1, 4} // 两个 value=1 的元素,id 分别为 2 和 4
    };

    // 非稳定排序(std::sort)
    std::sort(items.begin(), items.end(), [](const Item& a, const Item& b) {
        return a.value < b.value;
    });
    // 可能输出:{1,4}, {1,2}, {2,3}, {3,1} (id=4 和 id=2 的顺序可能交换)

    // 稳定排序(std::stable_sort)
    std::stable_sort(items.begin(), items.end(), [](const Item& a, const Item& b) {
        return a.value < b.value;
    });
    // 保证输出:{1,2}, {1,4}, {2,3}, {3,1} (id=2 始终在 id=4 之前)

    for (const auto& item : items) {
        std::cout << "(" << item.value << ", " << item.id << ") ";
    }
    return 0;
}

总结

  • 稳定排序:相等元素的相对顺序不变,适用于多关键字排序或需要保留原始顺序的场景。
  • 非稳定排序:不保证相等元素的顺序,但通常更快(如 std::sort)。
  • STL 选择
    • 需要稳定性时用 std::stable_sort
    • 仅需快速排序时用 std::sort
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值