SGISTL源码探究-stl_algo.h中的排序算法

STL中的sort源码分析 title: STL中的sort源码分析 date: 2020-12-08 20:43:11 tags: STL | source code categories: C++ | STL 前言 本文采用gcc5.4.0版本的STL进行分析,链接:在线源码。在下文的分析中都具体指出了对应文件的多少行,方便读者对照查看。如你想要在自己电脑上查看源码,相信你已经安装了gcc,STL绝大多数源码都位于/usr/include/c++/10.2.0/bits目录下。 我们都听说sort()内部是使用快速排序,但是实际. 阅读详情

前言

在本小节中,我们将分析STL中算法组件的最后一部分:排序算法。排序算法分为内部排序和外部排序。而内部排序中常见的有八种排序算法:直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序、桶排序。

在SGISTL实现的sort算法中,并不是简单的使用快速排序作为排序算法,而是交叉使用了插入排序、堆排序以及快速排序,并且做了一定的优化,并且只接受迭代器类型为RandomAccessIterator。这里不会详细去讲解这几种排序算法的原理,只简单介绍下排序的思想及流程并根据SGISTL实现的源码进行分析。

堆排序

基本思路

关于堆排序算法的实现思路就是:初始时把要排序的n个数的序列调整成一个堆,将堆顶元素取出,得到n个元素中最小(或最大)的元素,然后对前面(n-1)个元素重新调整使之成为堆,再取出堆顶元素,得到n 个元素中次小(或次大)的元素。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。称这个过程为堆排序。

关于堆排序,最重要的就两点:

  1. 如果将序列调整成堆;
  2. 取出堆顶元素之后,如果再次调整,使得剩下的元素依然为堆。关于这两点,在我们分析优先级队列前就已经对大根堆进行分析,如果你有所遗忘,建议回看(http://blog.youkuaiyun.com/move_now/article/details/77994869)。

接下来我们介绍partial_sort算法(排序部分采用堆排序),它会在sort算法的实现中被调用。

partial_sort

该算法的作用是接收一个middle迭代器,将[first, last)序列中的middle - first个最小元素以递增序列排在[first, middle)内,而剩下的[middle, last)个元素随意放置。partial_sort有两个版本,另外一个版本提供自己的比较仿函数comp,这里不做分析。

//函数名前加了两个下划线,这种命名方式的意义我们早就见怪不怪了,代表partial_sort的内部实现中会调用它
//通过参数我们可以知道partial_sort只接受迭代器类型为RandomAccessIterator
/* 实现思路:
 * 1. 将[first, middle)序列中的元素形成大根堆
 * 2. 遍历[middler, last)中的元素,如果比大根堆堆顶的元素小,则与之对调,然后重新调整堆
 * 3. 遍历完成之后,[first, middle)中的元素必然是前middle-first个小的元素
 * 4. 最后我们只需要对该堆进行排序即可(内部实现就是不断的调用pop_heap)
 */
template <class RandomAccessIterator, class T>
void __partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
                    RandomAccessIterator last, T*) {
  //构建堆
  make_heap(first, middle);
  //遍历[middle, last),找出比[first, middle)中还小的元素,进行调整
  for (RandomAccessIterator i = middle; i < last; ++i)
    if (*i < *first)
      __pop_heap(first, middle, i, T(*i), distance_type(first));
  //最后进行排序
  sort_heap(first, middle);
}

template <class RandomAccessIterator>
inline void partial_sort(RandomAccessIterator first,
                         RandomAccessIterator middle,
                         RandomAccessIterator last) {
  __partial_sort(first, middle, last, value_type(first));
}

直接插入排序

基本思路

直接插入排序的思想就是维护一个有序的左区间,将未排序部分的第一个元素插入到已排序左区间中合适的位置,中间可能涉及到寻找合适的位置而不断的比较。

该算法的时间复杂度为O(n^2),虽然看起来很慢,但是其实它特别适用于部分有序的序列,这样做的调整很少,并且对于少量数据来说也比较适合,因为快速排序、归并排序等效率较高的算法涉及到递归的函数调用,对于少量数据来说,这样反而比较慢,并且快排有个硬伤,那就是需要排序的序列已经部分有序甚至有序时,时间复杂度会从O(nlog2n)退化成O(n^2),由于还涉及到了大量的递归函数调用,效率还不如直接插入排序。

insertion_sort

在SGISTL实现直接插入排序中,提供了两个版本,版本二使用传入的比较仿函数comp进行比较,这里不做分析。并且实现过程中做了一定程度的优化,这点我们在它实现中可以看到。

源码如下:

/* 实现思路:
 * __insertion_sort中提供外循环,即左区间依次增大,直到覆盖整个序列
 * __linear_insert处理特殊情况及调用__unguarded_linear_insert处理普遍情况
 * __unguarded_linear_insert提供内循环,使得左区间有序
 */
template <class RandomAccessIterator>
void __insertion_sort(RandomAccessIterator first, RandomAccessIterator last) {
  //序列中元素个数为0,直接返回
  if (first == last) return;
  //外层循环,扩展有序区间([first, i))
  for (RandomAccessIterator i = first + 1; i != last; ++i)
    __linear_insert(first, i, value_type(first));
}

template <class RandomAccessIterator, class T>
inline void __linear_insert(RandomAccessIterator first,
                            RandomAccessIterator last, T*) {
  //value作为要插入的元素(i指向的元素)
  T value = *last;
  //特殊情况,若value比*first还小,那就不用一个一个比较找合适的位置了
  //直接把[first, last)后移一个位置
  //然后将头元素置为value
  if (value < *first) {
    copy_backward(first, last, last + 1);
    *first = value;
  }
  //处理普遍情况,内循环(寻找value可以插入的合适的位置)
  else
    __unguarded_linear_insert(last, value);
}

//内循环,为value寻找合适的插入位置并插入
//可以看到该函数命名的前缀是__unguarded,这个我们后面还会看到
//这是因为它并没有处理边界情况,即next是否到达first
//因为next并不会到达first,这种情况在__linear_insert已经处理了,所以在到达边界之前,一定会找到合适的位置插入
//这样就省下了一个判断,当数据量比较大的时候,效果还是比较显著
template <class RandomAccessIterator, class T>
void __unguarded_linear_insert(RandomAccessIterator last, T value) {
  RandomAccessIterator next = last;
  --next;
  /* 从(first, last)序列中从后往前依次寻找合适的插入位置
   * 若value比当前比较的元素小,证明还有可能可以前移也有可能当前位置就是插入点
   * 所以将*next的值后移,为前一个元素的后移或这value腾出位置
   * 将next指向前一个元素继续进行比较
   */
  while (value < *next) {
    *last = *next;
    last = next;
    --next;
  }
  //出循环代表找到了合适的插入点,进行赋值
  *last = value;
}

快速排序

快排的实现思路是选取序列中的任意一个元素当作枢轴(pivot),然后将小于枢轴的元素放在枢轴的左边,大于枢轴的元素放在枢轴的右边,再以该枢轴为中心,将左区间和右区间分别递归执行上面的操作。

实现的三个步骤:
1. 选择枢纽:在待排的序列中,以某种方式选择一个元素作为枢纽(pivot)
2. 分割操作:以该枢纽在序列中的位置,将该序列分成两个子序列。并且保证在枢纽左边的元素都比该枢纽小,在枢纽右边的元素都比枢纽大。
3. 分出来的两个子序列相当于是两个子问题,按照上面的步骤分别进行递归,直到序列为空或者只有一个元素。

比较经典的实现如下:

template <class RandomAccessIterator, class T>
RandomAccessIterator Partition(RandomAccessIterator first, RandomAccessIterator last, T pivot)
{
    while(true)
    {
        while(*first < pivot) ++first;      
        --last;
        while(*last > pivot) --last;   
        if(!(first < last)) return first;
        iter_swap(first, last);
        ++first;
    }
}
template <class RandomAccessIterator, class T>
void qsort(RandomAccessIterator first, RandomAccessIterator last)
{
    if(first != last)
    {
      RandomAccessIterator cut = Partition(first, last, *first);
      qsort(first, cut);
      qsort(cut, last);
    }
}
选取枢纽

做法一般是取首部/尾部元素作为枢纽,但是当序列是有序时,会导致效率急剧下降。
我们可以通过随机选择元素作为枢纽,这样有可能可以避免序列有序时效率的下降问题,但是最坏情况还是O(n^2),而且万一运气不好…..

比较好的做法是三数取中(median-of-three),即使用首部位置、中间位置、尾部位置这三个位置上的元素的中间值作为枢纽。比如首部为4,中间位置的元素为6,尾部位置上的元素为10,则选取中间位置的元素作为枢纽。事实上,SGISTL实现sort算法时就是采用的这种做法取枢纽。

三种优化
  1. 当分解的序列元素个数足够少时,可以采用直接插入排序。

    因为直接插入排序比较适合数据量少或者序列已经一定程序有序的情况,如果还是调用分解操作,又涉及到递归函数调用,效率反而不高。

  2. 减少递归的次数。

    众所周知,递归次数多了会爆栈。有n个元素就会调用n次递归函数,但是因为在qsort函数中,执行了一次递归之后,last或者first就没用了,我们可以选择其中一个递归以迭代的形式进行,使其只调用logn次递归。

    做法如下:

    template <class RandomAccessIterator, class T>
    void qsort(RandomAccessIterator first, RandomAccessIterator last)
    {
        while(first != last)
        {
          RandomAccessIterator cut = Partition(first, last, *first);
          qsort(cut, last);
          last = cut;
        }
    }
    1. 当序列有很多重复元素时,我们可以在执行分割时,把与枢纽相等的元素放入序列的两端,然后在分割之后,把与枢纽相等的元素移动到枢纽周围。这样下次分割时,就可以不对重复的元素进行操作了。具体的实现这里不做讨论。(因为sort实现中,只要使用的前面的优化)

内省排序

这种排序可能你没有听说过,其实我也没有。这个排序算法首先从快速排序开始,当递归深度超过一定深度(深度为排序元素数量的对数值)后转为堆排序。采用这个方法,内省排序既能在常规数据集上实现快速排序的高性能,又能在最坏情况下仍保持 O(nlogn)的时间复杂度。

SGISTL实现sort算法时就是采用的这种算法。所以总的来说,它即用到了快速排序,也用到了堆排序以及直接插入排序。

有了以上的铺垫,下面我们就进入到sort算法的真正实现中应该就比较容易了。

sort的实现

它的实现也提供了两个版本,另一个是传入comp仿函数进行比较,这里不做讨论。还有sort算法仅支持迭代器类型为RandomAccessIterator,这一点不要忘了。(所以list容器实现了自己的排序算法)

//计算递归深度(深度为排序元素数量的对数值)
//内省排序会通过递归的深度决定是否采用堆排序
template <class Size>
inline Size __lg(Size n) {
  Size k;
  for (k = 0; n > 1; n >>= 1) ++k;
  return k;
}

//三点定位,返回中间值
template <class T>
inline const T& __median(const T& a, const T& b, const T& c) {
  if (a < b)
    if (b < c)
      return b;
    else if (a < c)
      return c;
    else
      return a;
  else if (a < c)
    return a;
  else if (b < c)
    return c;
  else
    return b;
}

template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
  if (first != last) {
    //内省排序,最后一个参数即递归深度
    __introsort_loop(first, last, value_type(first), __lg(last - first) * 2);
    //该函数用于收尾工作,因为当元素数量低于一定程度时就会中止排序(以__stl_threshold表示数量个数多少的界定,值为16)
    //数量少了,就可以让直接插入排序开始工作了
    __final_insertion_sort(first, last);
  }
}

//内省排序
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
                      RandomAccessIterator last, T*,
                      Size depth_limit) {
  //优化,当元素个数大于16时,才进行排序
  while (last - first > __stl_threshold) {
    //depth_limit表示递归深度,由__lg函数计算得出
    //为0时,代表此时该启用堆排序了
    if (depth_limit == 0) {
      //堆排
      partial_sort(first, last, last);
      return;
    }
    //不为0,则减1,因为等下要调用递归了
    --depth_limit;
    //分割操作,__median选取三点中值
    RandomAccessIterator cut = __unguarded_partition
      (first, last, T(__median(*first, *(first + (last - first)/2),
                               *(last - 1))));
    //对右半递归进行sort
    __introsort_loop(cut, last, value_type(first), depth_limit);
    //优化,更新last,消除了一半的递归
    last = cut;
  }
}

//当__introsort_loop执行完之后,会有多个元素个数少于16的子序列并不是完全有序的,因为元素个数少于16个时会停止排序
//这个时候就该使用插入排序进行收尾了
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
                            RandomAccessIterator last) {
  //若当前序列的个数大于16个,则将该序列分割成两个序列,一个长度为16,另一个是剩余的序列,分别排序
  if (last - first > __stl_threshold) {
    //对前16个元素调用__insertion_sort排序
    __insertion_sort(first, first + __stl_threshold);
    //对剩余的序列进行排序
    __unguarded_insertion_sort(first + __stl_threshold, last);
  }
  //若当前序列的个数小于等于16个,调用__insertion_sort进行排序
  else
    __insertion_sort(first, last);
}

//调用__unguarded_insertion_sort_aux
template <class RandomAccessIterator>
inline void __unguarded_insertion_sort(RandomAccessIterator first,
                                RandomAccessIterator last) {
  __unguarded_insertion_sort_aux(first, last, value_type(first));
}

//直接插入排序,__unguarded_linear_insert函数前面分析过
template <class RandomAccessIterator, class T>
void __unguarded_insertion_sort_aux(RandomAccessIterator first,
                                    RandomAccessIterator last, T*) {
  for (RandomAccessIterator i = first; i != last; ++i)
    __unguarded_linear_insert(i, T(*i));
}

小结

由此可见sort算法并不是我们想象的那样简单的使用快排算法。我们再回顾一下它的优化点:

  1. 关于轴枢的选择,采用的是三点中值法确定轴枢,这是为了防止序列中的元素不够随机导致效率的退化
  2. 为了防止递归次数太多导致栈溢出,消除了部分递归
  3. 当元素个数比较少时,停止使用分割操作进行排序,而是留到最后使用直接插入排序进行处理
  4. 当递归的深度太深时,直接使用堆排序,这样可以将最坏情况推进到O(nlogn)

关于sort算法的讨论到此为止,迄今为止,我们已经分析了stl_algo.h中的大部分算法,相信你已经对该部分有一定的了解了。

在分析这些算法的时候,基本上每个算法都提供了具有仿函数的版本,在下一小节中,我们就将进入到STL六大组件之一的仿函数的分析中。

STL源码剖析——STL算法stl_algo.h 本文剖析的STL算法的源码,在剖析源码的同时会给出一些例子,这样加深对其理解,方便我们对这些算法的使用。 阅读详情

相关推荐

stl_algobase.h

#ifndef __SGI_STL_INTERNAL_ALGOBASE_H #define __SGI_STL_INTERNAL_ALGOBASE_H #ifndef __STL_CONFIG_H #include #endif #ifndef __SGI_STL_INTERNAL_RELOPS #include #endif #ifndef __SGI_STL_INTERNAL_PAIR_H #include #endif #ifndef __TYPE_TRAITS_H #include #endif #include #include #include #include #include #ifdef __STL_USE_NEW_IOSTREAMS #include #else /* __STL_USE_NEW_IOSTREAMS */ #include #endif /* __STL_USE_NEW_IOSTREAMS */ #ifndef __SGI_STL_INTERNAL_ITERATOR_H #include #include #endif

SGISTL源码探究-stl_algo.h中的基础算法

前言在上一小节中我们分析了stl_algobase.h中的算法,虽然都是一些比较基础的算法,但是了解其中的泛化以及特化的思想是很重要的。在本小节中我们将分析stl_algo.h中的算法,里面的大部分算法也很基础,比较复杂的我们放在另外的小节分析。各算法的实现for_each遍历[first, last),每个元素使用仿函数f进行处理。注意传入的迭代器类型是InputIterator,所以可能不支持赋

Move_now的博客 803

C++ STL库源代码(SGI版本)

C++ STL库源代码(SGI版本)

STL源代码剖析——STL算法stl_algo.h

前言     在前面的博文中剖析了STL的数值算法、基本算法和set集合算法。本文剖析STL其它的算法,比如排序算法、合并算法、查找算法等等。在剖析的时候。会针对函数给出一些样例说明函数的使用。源代码出自SGI STL中的&lt;stl_algo.h&gt;文件。注:本文的源代码许多,可能兴许博文会对这些算法进行归类分析。 STL算法剖析 #ifndef __SGI_STL_...

weixin_34416754的博客 275

【PVE9.1使用教程】

弹窗代码在 /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 中,通过 void({…}) 可以让弹窗部分代码不执行,实现删除弹窗的效果。安装过程这里不再赘述,记得不要使用网络版本进行安装,安装的时候不要使用镜像,否则安装过程会很卡。把下面的配置添加进去,允许同一个网段下的所以主机访问/mnt/pve_share文件夹。可以自己搭建也可以去咸鱼购买,本人在咸鱼上面购买的,暂时可用。也可以使用下面的命令,版本号需要自己查看最新的版本号。

weixin_42950821的博客 960

TSMaster如何用珠海创芯CAN卡实现高效CAN通信(附完整驱动安装指南)

本文详细介绍了如何使用TSMaster软件与珠海创芯CAN卡实现高效CAN通信,包括驱动安装、系统配置、ControlCAN.dll替换及TSMaster集成配置等关键步骤。通过实战指南和故障排除技巧,帮助工程师快速搭建稳定可靠的CAN通信测试环境,适用于汽车电子和工业控制等领域。

weixin_29201859的博客 479

五 STL算法(二)stl_algo.h

一  概述: 定义于SGI内的所有算法包含:heap算法(定义于中,stl_algo.h包含);set相关算法和其它的算法。 二 heap算法 (1)定义于中,被头文件#include。 (2)具体算法: *make_heap(): *push_heap(): *pop_heap(): *sort_heap(): 三 set相关算法(与常规的集合操作不同)

linux系统、网络编程和分布式计算 1120

模电学习笔记(十二)——跨阻放大器

模电学习笔记(十二) 跨阻放大器 跨组运算放大器是将电流信号转换成为电压信号,电流到电压增益基于反馈电阻。 设计目标: 输入 输出 带宽 电源 0A 100uA 0V 7V 20kHz 15V -15V 1.计算R1的值(增益电阻器) 2.计算C1的值满足电路带宽 ...

tang11081023的博客 2万+

SGISTL源码探究-STL中的算法(前言)

前言我们目前已经分析了STL中的六大组件的一半。剩下的还有算法、仿函数、配接器,已经分析了配置器、迭代器、容器部分。接下来进入到剩下的三大组件中最复杂的算法部分,关于STL中的算法,它实现了很多功能,但是分析这部分的时候我只打算选择一部分比较经典的算法进行分析(因为这部分的算法实在是太多了),只要掌握了分析的方法,以后自己遇到其他的STL算法或者感兴趣的,直接阅读源码就行了。概览大致分类STL中的算

Move_now的博客 589

Anomalib实战指南:从零开始构建自定义异常检测数据集

本文提供了一份详细的Anomalib实战指南,指导用户从零开始构建自定义异常检测数据集。文章深入解析了数据准备的核心步骤、目录结构规范,并对比了PatchCore与FastFlow等关键模型的适用场景。通过清晰的代码示例,手把手演示了环境配置、模型训练与推理评估的全流程,旨在帮助开发者快速掌握这一工业视觉异常检测利器,有效解决实际生产中的缺陷识别难题。

weixin_29054245的博客 643

FPGA串口通信----uart(一)

通过PLL锁相环IP的使用,可以输入时钟进行分频,倍频,也可以产生多路时钟输出信号。外部提供晶振的原因:①Fpga电路大多数需要时序分析②晶振在Fpga内部占空间大,所以放置于外部PCB板上Uart异步传输速率不能很快的原因:考虑到工程实际问题,假如时钟周期大(传输速率慢的话),采取到数据电平变化的边沿时刻的概率会小很多,这样数据也很准确,通常uart适用于2M.

mvpkuku的博客 970

STL算法之基本算法<stl_algobase.h>

STL标准规格中没哟区分基本算法或复杂算法,然后SGI却把常用的一些算法定义于之中,其他算法定义于之中。以下一一列举这些基本算法。

chnming1987的博客 1325

多模态目标检测综述介绍及框架提供

多模态目标检测是计算机视觉领域的前沿方向,旨在通过融合不同传感器或数据源的信息(如可见光、红外、深度等),提升复杂场景下目标检测的准确性和鲁棒性。

Limiiiing的博客 4588

STL 源码剖析 算法 stl_algo.h -- merge sort

merge sort ---------------------------------------------------------------------- 描述:归并排序 思路: 1.将区间对半分割 2.对左、右段分别排序 3.利用inplace_merge将左、右段合并成为一个完整的有序序列 复杂度:O(log n) 源码: template<class BidirectionalIter> void mergesort(BidirectionalIter first, Bidirecti

1298

华为OD机试 - 计算数列位置N的值 - 模拟法(Python/JS/C/C++ 新系统 100分)

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。输入 M,N 两个数,则按照以下规则形成一个数列。数列的前 M 个元素的值为 1 到 M从 M+1 个元素开始,计算逻辑为如果其前 M 个元素中,存在值相同的元素,则该位置上的数值等于前 M 个数中最大数值与最小数值之和。如果其前 M 个元素中,

学Java,找哪吒 508

实战|2026美团&大众点评餐饮数据抓取:Playwright/Selenium反爬全攻略

核心结论:2026年美团&大众点评的反爬核心是“多维度风控”,需组合使用“住宅IP+设备指纹伪装+真人行为模拟+动态验证处理”,Playwright是最优工具,Selenium仅作为补充。效率优化:单机爬取速度建议控制在“每小时500-800条”,避免高频请求触发风控;分布式爬取需确保每个节点使用独立住宅IP,且行为轨迹不一致。扩展方向集成WASM解密工具,破解2026年美团的Token加密;用AI识别动态点选验证,提升验证通过率;对接大数据平台,对抓取的餐饮数据进行可视化分析。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2461

STL源码分析之stl_algo.h中的基本算法

前言 上一节分析了stl_algo.h中的rotate函数实现, 本节我们继续分析该文件的中的其他基本算法, 这些算法功能实现看似很简单, 但是这些算法都能进行衍生, 用户自定义, 简单化了我们的部分编程, 直接使用无需再定义. 基本算法 for_each 将[first, last) 范围的元素由传入仿函数(函数)进行处理, 最后返回仿函数(函数). template &lt;class Inp...

啦啦啦 991

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

STL源码剖析——仿函数(函数对象)

1 仿函数也称为函数对象,是一种具有函数特质的对象。调用者可以像函数一样的使用这些对象,例如在很多STL算法中,都可以看到,我们可以将一个方法作为模板内的参数传入到算法实现中,例如sort的时候我们可以根据我们传入的自定义的compare函数来进行比较排序。解决办法是使用函数指针,或者是将这个“操作”设计为一个所谓的仿函数,再用这个仿函数生成一个对象,并用这个对象作为算法的一个参数。

Smile&搁浅 1016

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

STL源码剖析——stl_algobase.h

STL标准中没有区分基本算法或复杂算法,单SGI把常用的一些算法定义在只中,其他算法定义在中。 stl_algobase.h中的算法,比较值得学习的是copy(),它“无所不用其极”的改善效率。copy的目的是复制一段元素到指定区间,复制操作最容易想到赋值操作符=,但是有的赋值操作符=是trivial的,可以直接拷贝。关于赋值操作符=是不是trivial的,可以参考“Member

Smile&搁浅 3763

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

桶排序(最快最简单的排序)

第十一章 23 // An highlighted block def bucketSort(nums): max_num = max(nums) # 创建一个元素全是 0 的列表, 当做桶 bucket = [0]*(max_num+1) print(bucket) # 把所有元素放入桶中, 即把对应元素个数加一 for i in nums: ...

qq_turn 2363

STL algorithm源码:stl_algo.h

// Algorithm implementation -*- C++ -*- // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, // 2010, 2011 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C

roaylchen的博客 6911

STL学习笔记----8.STL仿函数

一. 概念: 函数对象function objects,又名仿函数,是一个定义了operator()操作的对象。 class FunctionObjectType { public: void operator() { statements } }; 二. 仿函数当做排序准则: 程序员经常需要将某些class objec

脚踏实地,仰望星空 2344

C++ 有哪些奇淫巧技之仿函数

一、理论: 二、仿函数应用场景: 三、仿函数的实现 一、理论: 1.C++仿函数本质上是一个类,而不是一个函数. 2.其实现方式是对class的()操作符重载,让其拥有类似于函数的功能 二、仿函数应用场景: 若需要对一个vector&amp;amp;lt;`string&amp;amp;gt;进行字符串长度小于10的计数,你的代码可能是这样的: 幼年期: bool cmp(co...

程序员の墨梅 700

桶排序、仿函数

桶排序 桶排序不是基于比较的排序,它只能用于对基本数据类型进行排序,只与具体业务有关。 1. 计数排序 某公司有员工10人,员工的年龄在20到50之间,请对员工的年龄进行排序。 用计数排序对员工进行排序: 创建容器数组arr[50 - 20 + 1]; 依次统计每个年龄有多少人,即arr[0]储存20岁的员工有多少人,arr[1]存储21岁有多少人。。。。。。 按照数组arr的顺序依次...

weixin_44233369的博客 164

SGISTL源码探究-STL中的红黑树(上)

前言本小节将进入到SGISTL的红黑树部分。关于红黑树,是一种比较复杂的数据结构,但是并不是特别难。如果对红黑树不太了解,可以去网上查阅相关的资料,因为本文的主要目的是分析STL中的红黑树的源码,和普通的红黑树略有不同,还要复杂一些,需要有一定的基础。基本概念首先什么是二叉搜索树,二叉搜索树即符合任何一个节点的值一定大于其左子树的任何一个节点的值并且小于其右子树的任何一个节点的值(节点的值不允许重复

Move_now的博客 1806
上一篇: SGISTL源码探究-stl_algo.h中的排列算法
下一篇: SGISTL源码探究-仿函数
UKey_
博客等级 码龄10年 258粉丝 186原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值