C++STL中sort排序算法的底层实现方式和常见问题

STL其他内容解析:关于C++中STL的理解和应用


常见问题:

  • 数据量大和数据量小都适合用快速排序吗?
  • 快速排序的时间复杂度不是稳定的nlogn,最坏情况会变成n^2,怎么解决复杂度恶化问题?
  • 快速排序递归实现时,怎么解决递归层次过深的问题?
  • 递归过深会引发什么问题?
  • 怎么控制递归深度?如果达到递归深度了还没排完序怎么办?

并非所有容器都使用sort算法

既然问的是STL的sort算法实现,那么先确认一个问题,哪些STL容器需要用到sort算法?
首先,关系型容器拥有自动排序功能,因为底层采用RB-Tree,所以不需要用到sort算法。
其次,序列式容器中的stack、queue和priority-queue都有特定的出入口,不允许用户对元素排序。
剩下的vector、deque,适用sort算法。

实现逻辑

STL的sort算法,数据量大时采用快速排序算法,分段归并排序。一旦分段后的数据量小于某个门槛(16),为避免QuickSort快排的递归调用带来过大的额外负荷,就改用插入排序。如果递归层次过深,还会改用堆排序。

所以,STL的sort是结合快速排序-插入排序-堆排序三种排序算法的一种排序实现。

思考:

1.为什么对于区间小于16的采用插入排序,如果递归深度恶化改用堆排序?

   插入排序对于基本有序数据较少的序列很高效。

   堆排序的时间复杂度固定为O(nlogn),不需要再递归下去了。

2.那堆排序既然也是O(nlogn)直接用堆排序实现sort不行吗?为啥用快速排序实现?

    第一点,堆排序数据访问的方式没有快速排序友好。对于快速排序来说,数据是顺序访问的。而对于堆排序来说,数据是跳着访问的。 比如,堆排序中,最重要的一个操作就是数据的堆化。比如下面这个例子,对堆顶节点进行堆化,会依次访问数组下标是 1,2,4,8 的元素,而不是像快速排序那样,局部顺序访问,所以,这样对 CPU 缓存是不友好的。

  第二点,对于同样的数据,在排序过程中,堆排序算法的数据交换次数要多于快速排序。我们在讲排序的时候,提过两个概念,有序度和逆序度。对于基于比较的排序算法来说,整个排序过程就是由两个基本的操作组成的,比较和交换(或移动)。快速排序数据交换的次数不会比逆序度多。

对结构体sort

需要写cmp函数,调用 (数组名称, 数组名称+数组长度, cmp);

#include <iostream>
#include <map>
#include <utility>
#include <memory>
#include <queue>
#include <algorithm>
#include <cstdio>
using namespace std;

struct Edge {
    int u, v, w;
};
Edge t[100000];

bool cmp(const Edge &x, const Edge &y)
{
    if (x.w == y.w) {
        if (x.v == y.v) {
            cout << "ufdfnn" << endl;
            return x.u < y.u;
        }
        return x.v < y.v;
    }
    return x.w < y.w;
}

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        t[i].u = u;
        t[i].v = v;
        t[i].w = w;
    }
    cout << endl;
    
    sort(t, t + m, cmp);  // 左臂右开

    for (int i = 0; i < m; ++i) {
        cout << t[i].u << " " << t[i].v << " " << t[i].w << endl;
    }
}

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C++11STL常用的排序算法有以下几种: 1. sort sortSTL最常用的排序算法,它可以对容器的元素进行排序。sort的时间复杂度为O(NlogN),使用快速排序算法实现sort的基本使用方法如下: ```c++ sort(begin, end); // 对区间[begin, end)内的元素排序 ``` 其,`begin`和`end`分别是容器要排序的元素的起始和结束迭代器。 此外,sort还可以接受一个可调用对象作为参数,来实现自定义的排序方法。例如,可以按照元素的某个属性进行排序: ```c++ sort(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.property < b.property; }); // 按照元素的property属性进行排序 ``` 2. stable_sort stable_sortsort的用法类似,也可以对容器的元素进行排序,但它保证了相等元素的相对顺序不会发生改变。stable_sort的时间复杂度为O(NlogN),使用归并排序算法实现。stable_sort的基本使用方法如下: ```c++ stable_sort(begin, end); // 对区间[begin, end)内的元素排序 ``` 3. partial_sort partial_sort可以对容器的元素进行部分排序,即只将前k个最小(或最大)的元素放在容器的前k个位置上。partial_sort的时间复杂度为O(Nlogk),使用堆排序算法实现。partial_sort的基本使用方法如下: ```c++ partial_sort(begin, middle, end); // 将区间[begin, end)内的前middle-begin个元素排序,其他元素保持原有顺序 ``` 其,`middle`是一个迭代器,指向容器排序后前middle-begin个元素的末尾位置。 4. nth_element nth_element可以找出容器第k小(或第k大)的元素。nth_element的时间复杂度为O(N),使用快速选择算法实现。nth_element的基本使用方法如下: ```c++ nth_element(begin, nth, end); // 将区间[begin, end)内的元素排序,使得第nth个元素是第nth小的元素 ``` 其,`nth`是一个迭代器,指向容器第nth小的元素。 以上就是C++11STL常用的排序算法,可以根据实际需求选择适合的算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值