STL容器实战:从基础到高级的排序问题解析

1. 理解STL容器的排序机制

STL容器作为C++标准库的核心组件,提供了多种高效的数据结构和算法实现。其中排序功能是日常开发中最常用的操作之一。理解不同容器的排序特性,能够帮助我们针对具体场景选择最优解决方案。

vector的排序特性

  • 连续内存布局,支持随机访问
  • 默认使用快速排序算法(std::sort)
  • 时间复杂度为O(N log N)
  • 支持自定义比较函数
vector<int> nums = {3,1,4,1,5,9};
sort(nums.begin(), nums.end());  // 默认升序
sort(nums.begin(), nums.end(), greater<int>());  // 降序

map的排序特性

  • 基于红黑树实现,元素自动按键排序
  • 插入时即保持有序状态
  • 键值不可修改(const Key)
  • 查找时间复杂度O(log N)

pair在排序中的应用

  • 将两个数据成员绑定为一个单元
  • first成员默认作为主排序键
  • 无需自定义比较函数即可实现多级排序

2. 基础排序实战:vector与pair的组合应用

2.1 单字段排序

最简单的排序场景是对单一数据类型进行排序:

vector<string> names = {"Alice", "Bob", "Charlie"};
sort(names.begin(), names.end());  // 字典序排序

2.2 多字段排序

使用pair实现多级排序时,STL已经内置了比较逻辑:

比较规则说明
先比较first如果first不等,按first排序
再比较second如果first相等,按second排序
vector<pair<int, string>> people = {
    {25, "Alice"}, 
    {20, "Bob"}, 
    {25, "Charlie"}
};
sort(people.begin(), people.end());  // 自动按年龄和姓名排序

2.3 自定义排序规则

当默认排序不满足需求时,可以自定义比较函数:

bool customCompare(const pair<int, string>& a, const pair<int, string>& b) {
    if(a.first != b.first) 
        return a.first > b.first;  // 年龄降序
    return a.second < b.second;    // 姓名升序
}
sort(people.begin(), people.end(), customCompare);

3. 进阶排序技术:map的特殊排序场景

3.1 map按值排序的挑战

map本身按键排序,但实际业务中常需要按值排序。解决方案是将map转换为vector再排序:

map<string, int> wordCount = {{"apple",5}, {"banana",2}, {"cherry",8}};
vector<pair<string, int>> vec(wordCount.begin(), wordCount.end());

sort(vec.begin(), vec.end(), 
    [](const auto& a, const auto& b) { 
        return a.second > b.second; 
    });

3.2 保留插入顺序的排序

使用vector保存插入顺序,同时用map快速查找:

vector<string> insertionOrder;
map<string, int> dataMap;

void addItem(const string& key, int value) {
    if(dataMap.find(key) == dataMap.end()) {
        insertionOrder.push_back(key);
    }
    dataMap[key] = value;
}

3.3 多级map排序

对于嵌套map结构,需要逐层处理:

map<int, map<string, int>> multiMap;
// 填充数据...

// 对第二层map按值排序
for(auto& outer : multiMap) {
    vector<pair<string, int>> temp(outer.second.begin(), outer.second.end());
    sort(temp.begin(), temp.end(), 
        [](const auto& a, const auto& b) { return a.second > b.second; });
    
    outer.second.clear();
    for(const auto& item : temp) {
        outer.second.insert(item);
    }
}

4. 性能优化与特殊场景处理

4.1 排序算法选择

STL提供了多种排序算法,针对不同场景选择最优解:

算法特点适用场景
sort快速排序实现,不稳定通用排序
stable_sort归并排序实现,稳定需要保持相等元素顺序
partial_sort部分排序只关心前N个元素
nth_element快速选择找第N大元素
vector<int> bigData(1000000);
// 只需要前100个最小元素
partial_sort(bigData.begin(), bigData.begin()+100, bigData.end());

4.2 大对象排序优化

对于大型对象,避免拷贝提升性能:

vector<LargeObject> objects;
// 使用指针排序避免拷贝
sort(objects.begin(), objects.end(), 
    [](const LargeObject& a, const LargeObject& b) {
        return a.key < b.key;
    });

4.3 自定义对象排序

为自定义类实现比较运算符:

struct Person {
    string name;
    int age;
    
    bool operator<(const Person& other) const {
        return age < other.age;
    }
};

vector<Person> people;
sort(people.begin(), people.end());  // 使用重载的<运算符

5. 实战案例解析

5.1 学生成绩排名系统

struct Student {
    string name;
    int score;
    string classId;
};

vector<Student> students;
// 按班级分组后按成绩降序排序
map<string, vector<Student>> byClass;
for(const auto& s : students) {
    byClass[s.classId].push_back(s);
}

for(auto& [classId, classStudents] : byClass) {
    sort(classStudents.begin(), classStudents.end(),
        [](const Student& a, const Student& b) {
            return a.score > b.score;
        });
    
    cout << "Class " << classId << " ranking:\n";
    for(size_t i = 0; i < classStudents.size(); ++i) {
        cout << i+1 << ". " << classStudents[i].name 
             << ": " << classStudents[i].score << "\n";
    }
}

5.2 股票交易数据分析

map<string, vector<pair<time_t, double>>> stockHistory;

// 对每支股票按时间排序
for(auto& [stock, records] : stockHistory) {
    sort(records.begin(), records.end(),
        [](const auto& a, const auto& b) {
            return a.first < b.first;  // 按时间戳升序
        });
    
    // 计算日收益率
    vector<double> returns;
    for(size_t i = 1; i < records.size(); ++i) {
        double ret = (records[i].second - records[i-1].second) / records[i-1].second;
        returns.push_back(ret);
    }
}

5.3 社交网络好友推荐

map<string, set<string>> userFriends;
map<string, int> commonFriends;

// 计算共同好友数
for(const auto& [user, friends] : userFriends) {
    for(const auto& friendName : friends) {
        for(const auto& potentialFriend : userFriends[friendName]) {
            if(potentialFriend != user && 
               !friends.count(potentialFriend)) {
                commonFriends[potentialFriend]++;
            }
        }
    }
}

// 按共同好友数排序推荐
vector<pair<string, int>> recommendations(commonFriends.begin(), commonFriends.end());
sort(recommendations.begin(), recommendations.end(),
    [](const auto& a, const auto& b) {
        return a.second > b.second;
    });

更多推荐