STL 源码剖析:sort
我大抵是例程太闲了。
更好的源码源程阅读体验。
sort 作为最常用的序代 STL 之一,大多数人对于其了解仅限于快速排序。码例
听说其内部实现还包括插入排序和堆排序,例程于是源码源程h5 源码 动物很好奇,决定通过源代码一探究竟。序代
个人习惯使用 DEV-C++,码例不知道其他的例程编译器会不会有所不同,现阶段也不是源码源程很关心。
这个文章并不是序代析完之后的总结,而是码例边剖边写。不免有个人的例程猜测。而且由于本人英语极其差劲,源码源程大抵会犯一些憨憨错误。序代
源码部分sort
首先,在 Dev 中输入以下代码:
然后按住 ctrl,鼠标左键sort,就可以跳转到头文件 stl_algo.h,并可以看到这个:
注释、小说单页源码模板和函数参数不再解释,我们需要关注的是函数体。
但是,中间那一段没看懂……
点进去,是一堆看不懂的#define。
查了一下,感觉这东西不是我这个菜鸡能掌握的。
有兴趣的 戳这里。
那么接下来,就应该去到函数__sort 来一探究竟了。
__sort
通过同样的方法,继续在stl_algo.h 里找到 __sort 的源代码。
同样,只看函数体部分。
一般来说,sort(a,a+n) 是对于区间 [公式] 进行排序,所以排序的前提是 __first != __last。
如果能排序,那么通过两种方式:
一部分一部分的lua脚本引擎源码看。
__introsort_loop
最上边注释的翻译:这是排序例程的帮助程序函数。
在传参时,除了首尾迭代器和排序方式,还传了一个std::__lg(__last - __first) * 2,对应 __depth_limit。
while 表示,当区间长度太小时,不进行排序。
_S_threshold 是一个由 enum 定义的数,好像是叫枚举类型。
当__depth_limit 为 [公式] 时,也就是迭代次数较多时,不使用 __introsort_loop,而是使用 __partial_sort(部分排序)。
然后通过__unguarded_partition_pivot,得到一个奇怪的位置(这个函数的翻译是无防护分区枢轴)。
然后递归处理这个奇怪的位置到末位置,再更新末位置,继续循环。应用商店源码代码
鉴于本人比较好奇无防护分区枢轴是什么,于是先看的__unguarded_partition_pivot。
__unguarded_partition_pivot
首先,找到了中间点。
然后__move_median_to_first(把中间的数移到第一位)。
最后返回__unguarded_partition。
__move_median_to_first
这里的中间数,并不是数列的中间数,而是三个迭代器的中间值。
这三个迭代器分别指向:第二个数,中间的数,最后一个数。
至于为什么取中间的数,暂时还不是很清楚。
`__unguarded_partition`
传参传来的序列第二位到最后。
看着看着,我好像悟了。
这里应该就是实现快速排序的部分。
上边的proxy0源码__move_median_to_first 是为了防止特殊数据卡 [公式] 。经过移动的话,第一个位置就不会是最小值,放在左半序列的数也就不会为 [公式] 。
这样的话,__unguarded_partition 就是快排的主体。
那么,接下来该去看部分排序了。
__partial_sort
这里浅显的理解为堆排序,至于具体实现,在stl_heap.h 里,不属于我们的讨论范围。
(绝对不是因为我懒。)
这样的话,__introsort_loop 就结束了。下一步就要回到 __sort。
__final_insertion_sort
其中某常量为enum { _S_threshold = };。
其中实现的函数有两个:
__insertion_sort
其中的__comp 依然按照默认排序方式 < 来理解。
_GLIBCXX_MOVE_BACKWARD3
进入到_GLIBCXX_MOVE_BACKWARD3,是一个神奇的 #define:
其上就是move_backward:
上边的注释翻译为:
__unguarded_linear_insert
翻译为“无防护线性插入”,应该是指直接插入吧。
当__last 的值比前边元素的值小的时候,就一直进行交换,最后把 __last 放到对应的位置。
__unguarded_insertion_sort
就是直接对区间的每个元素进行插入。
总结
到这里,sort 的源代码就剖完了(除了堆的那部分)。
虽然没怎么看懂,但也理解了,sort 的源码是在快排的基础上,通过堆排序和插入排序来维护时间复杂度的稳定,不至于退化为 [公式] 。
鬼知道我写这么多是为了干嘛……
FFmpeg 流媒体处理 - 收流与推流
流媒体技术的定义与应用
流媒体,作为多媒体应用技术的一种,指的是通过网络进行分段传输的连续媒体数据,实现即时播放的一种技术与过程。这种技术使得数据包能像流水一样快速传输,避免了必须下载整个媒体文件的传统方式。关于流媒体的基础概念,可参考观止云的“流媒体|从入门到出家”系列文章,了解更多深入信息。
FFmpeg中的流媒体处理层次
FFmpeg在处理音视频数据时,划分了四个层次:协议层、容器层、编码层和原始数据层。协议层提供网络协议收发功能,包括libavformat库与第三方库的支持;容器层处理各种封装格式,由libavformat库提供;编码层负责音视频编码和解码,由libavcodec库与第三方编解码库支持;原始数据层处理未编码的原始音视频帧,由libavfilter库提供支持。本文提及的收流与推流功能,属于协议层的处理。
FFmpeg的协议与封装格式处理
在FFmpeg中,libavformat库提供了丰富的协议处理和封装格式处理功能。在打开输入/输出时,FFmpeg会根据URL来探测输入/输出格式,选择合适的协议和封装格式。例如,输出URL为"rtmp://..0./live"时,FFmpeg会确定使用rtmp协议,封装格式为flv。
流媒体系统中的角色
流媒体系统涉及三个主要角色:流媒体服务器、推流客户端和收流客户端。推流客户端是内容生产者,收流客户端是内容消费者。推流客户端将内容推送到流媒体服务器,收流客户端则从流媒体服务器获取内容。
收流与推流功能
当输入为网络流,输出为本地文件时,实现收流功能,即将网络流存储为本地文件;当输入为本地文件,输出为网络流时,实现推流功能,即将本地文件推送到网络;当输入和输出均为网络流时,实现转流功能,即将一个流媒体服务器上的流推送到另一个流媒体服务器。
相关视频推荐
相关视频推荐
免费学习地址
免费分享资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击加群免费领取哦~
源码与转封装例程
源码与转封装例程大部分相同,可视为转封装例程的增强版。收流代码与打开普通文件的代码无异,FFmpeg能识别流协议及封装格式,使用相应的协议层代码接收流,处理后的数据与普通文件内容一致。推流需要注意封装格式指定和流媒体服务器的处理速度。
测试与验证
测试需要搭建流媒体服务器,推荐使用nginx-rtmp服务器。搭建时,可使用docker镜像简化过程。通过配置docker服务、镜像加速、拉取nginx-rtmp镜像、打开容器、防火墙添加例外端口等步骤完成搭建。测试文件下载、ffmpeg推流、ffplay收流播放,验证服务器功能。
编译与测试
下载例程源码后,执行shell命令下载,并在源码目录执行./compile.sh生成streamer可执行文件。测试文件下载与推流、收流功能,确保系统正常运行。
遗留问题
推流和收流过程中,可能出现结束信息输出,提示程序退出。此类问题通常与系统资源或配置相关,需要根据实际情况进行排查和调整。
2024-11-29 23:47
2024-11-29 23:42
2024-11-29 23:27
2024-11-29 22:56
2024-11-29 22:53