STL 源码剖析:sort
我大抵是太闲了。
更好的码剖阅读体验。
sort 作为最常用的析样 STL 之一,大多数人对于其了解仅限于快速排序。码剖
听说其内部实现还包括插入排序和堆排序,析样原画psd源码于是码剖很好奇,决定通过源代码一探究竟。析样
个人习惯使用 DEV-C++,码剖不知道其他的析样编译器会不会有所不同,现阶段也不是码剖很关心。
这个文章并不是析样析完之后的总结,而是码剖边剖边写。不免有个人的析样猜测。而且由于本人英语极其差劲,码剖大抵会犯一些憨憨错误。
源码部分sort
首先,在 Dev 中输入以下代码:
然后按住 ctrl,鼠标左键sort,就可以跳转到头文件 stl_algo.h,并可以看到这个:
注释、模板和函数参数不再解释,我们需要关注的是函数体。
但是,中间那一段没看懂……
点进去,是一堆看不懂的#define。
查了一下,感觉这东西不是我这个菜鸡能掌握的。
有兴趣的 戳这里。
那么接下来,就应该去到函数__sort 来一探究竟了。
__sort
通过同样的方法,继续在stl_algo.h 里找到 __sort 的源代码。
同样,只看函数体部分。
一般来说,租友系统源码sort(a,a+n) 是对于区间 [公式] 进行排序,所以排序的前提是 __first != __last。
如果能排序,那么通过两种方式:
一部分一部分的看。
__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`
传参传来的序列第二位到最后。
看着看着,我好像悟了。
这里应该就是实现快速排序的部分。
上边的__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 的源码是在快排的基础上,通过堆排序和插入排序来维护时间复杂度的稳定,不至于退化为 [公式] 。
鬼知道我写这么多是为了干嘛……
有哪些值得推荐的C++书籍?
C++是一种广泛使用的编程语言,有许多优秀的书籍可以帮助你深入学习和理解它。以下是一些值得推荐的C++书籍: 1.《C++Primer》:这是一本非常经典的C++入门书籍,适合初学者。它详细介绍了C++的基本概念和语法,并提供了大量的示例代码和练习题。 2.《EffectiveC++》:这本书由ScottMeyers撰写,是一本关于C++最佳实践的指南。它涵盖了许多重要的主题,如内存管理、异常处理和泛型编程等,对于提高C++编程技巧非常有帮助。 3.《深入理解计算机系统》:这本书虽然不是专门讲解C++的,但它对计算机系统的底层原理进行了深入的探讨,包括处理器、内存和操作系统等方面。这对于理解C++的运行机制和优化代码非常有帮助。 4.《STL源码剖析》:这本书由NicolaiM.Nestorov撰写,深入剖析了C++标准模板库(STL)的实现原理。通过阅读这本书,你可以更好地理解STL的工作原理,并学会如何高效地使用STL。 5.《设计模式:可复用面向对象软件的基础》:这本书介绍了常见的设计模式,如单例模式、工厂模式和观察者模式等。虽然它是以Java为例进行讲解的,但其中的思想和原则同样适用于C++编程。 6.《算法导论》:这本书是计算机科学领域的经典教材,介绍了各种常见的算法和数据结构。虽然它不是专门讲解C++的,但对于提高算法设计和分析能力非常有帮助。C++从入门到进阶的参观预约系统源码系列书籍推荐
要多读书,读好书!学习任何技能,阅读经典书籍都是不可或缺的一步。C++从入门到进阶,需要扎实的基础和深入的理解。接下来,我们将推荐一系列从入门到进阶的C++经典书籍,帮助您全面提升编程技能。1. C++入门书籍
了解C++之前,首先需要掌握C语言的基础。以下两本书是学习C语言的经典教材。1.1 C语言程序设计(谭浩强)
本书被广泛采用为学习C语言的教材,通俗易懂,是初学者的必备读物。我在解决编译问题时,翻阅了该书的相关章节,精准的表述让我恍然大悟,很多学生时代未理解的内容,有了工作经验后,豁然开朗。1.2 C++ Primer 中文版(第5版)
这是一本学习C++语言的经典入门教材,详细讲解了C++语言的基础语法和概念。最新版全面采用C++标准,体现了C++语言的重大进展。丰富的教学辅助内容、醒目的知识点提示和精心组织的编程示范,使得本书在C++领域内权威地位稳固。2. VC++/MFC书籍
在掌握C++基础后,可以从简单的Windows编程开始,逐步熟悉Visual Studio开发工具的使用。MFC虽然在大型商用项目中已较少使用,但它作为经典UI框架,对编写小型工具软件依然有重要作用。2.1 VC++深入详解(孙鑫)
这是一本学习Windows编程的入门经典教材,由浅入深地讲述Windows程序的内部运行机制、MFC框架、文本、菜单、对话框、文件操作、网络编程等多个主题。2.2 深入浅出MFC(侯捷)
本书深入学习MFC编程,分为四大篇,从学习MFC程序设计的基础到Visual C++开发环境,再到MFC核心程序,最后通过微软附带的Scribble程序实例,深入讲解Runtime Type Information、Dynamic Creation、Persistence、message Mapping、Command Routing等核心技术。3. C++进阶书籍
在具备一定开发经验后,需要深入理解C++特性,提高编写C++代码的效率和稳定性。3.1 Effective C++:改善程序与设计的个具体做法(第3版)(Scott Meyers著)
Scott Meyers的成名之作,是提升C++功力的绝佳契机。阅读这本书后,您的C++技能将显著提升。3.2 More Effective C++:个改善编程与设计的有效方法(Scott Meyers著)
本书是Scott Meyers Effective系列的进阶版本,深入解析C++编译器如何解释代码,助您编写出更健壮的软件。3.3 STL源码剖析(侯捷)
深入了解STL的内部实现,本书详细讲解了vector、list、heap、deque、Red Black tree、hash table等数据结构的实现,让您掌握各种算法的实现。4. Windows编程书籍
从事Windows应用程序开发的人,以下两本书是经典的选择,深入了解Windows系统特性。4.1 Win多线程程序设计(Jim Beveridge / Robert Wiener)
全书详细讲解Windows系统中的多线程编程技术,包括线程的启动和结束、核心对象、同步机制及其用途。4.2 Windows核心编程(Jeffrey Richter / christophe Nasarre)
本书是深入理解Windows特性的必备参考书,全面讲解Windows核心编程,引领数万程序员步入Windows开发领域。5. Linux书籍
Linux系统广泛应用于各种服务器,作为C++开发人员,学习Linux知识与技能至关重要。5.1 鸟哥的Unux私房菜
本书全面介绍了Linux系统的基本原理,适合初学者入门。5.2 Linux内核源代码情景分析
本书采用情景会话教学法,全面剖析Linux内核源代码,深入理解Linux系统特性。6. 汇编与软件调试书籍
掌握一定的汇编语言基础和软件调试技能,对于解决C++程序问题至关重要。6.1 汇编语言(王爽)
本书系统讲解汇编语言,为初学者提供循序渐进的学习路径。6.2 IDA Pro权威指南(Chris Eagle)
IDA Pro是应用广泛的静态反汇编工具,本书深入讲解其使用方法。6.3 软件调试(张银奎)
本书全面展示软件调试技术,是深入理解软件和自由驾驭软件的宝贵资料。6.4 格蠹汇编:软件调试案例集锦
本书通过具体案例解析软件调试,适合程序员和信息安全研究者阅读。7. 网络及TCP/IP协议
学习网络知识,掌握排查网络问题的方法是C++程序开发人员的必备技能。7.1 计算机网络(谢希仁)
本书系统介绍了计算机网络的基本原理和各种网络技术。7.2 TCP/IP详解(卷1、卷2、卷3)
本书从协议、实现和TCP事务协议等多个角度深入讲解TCP/IP协议。8. 设计模式、数据结构与算法
掌握设计模式、数据结构和算法是提高编程能力的关键。8.1 boost程序库完全开发指南(罗剑锋)
本书详细介绍boost库,帮助读者迅速掌握其用法和实际开发应用。8.2 大话设计模式(程杰)
本书以问答形式讲解设计模式,引导初学者理解设计背后的智慧。8.3 设计模式:可复用面向对象软件的基础(Erich Gamma / Richard Helm / Ralph Johnson)
本书精选个设计模式,总结面向对象设计中最有价值的经验。8.4 数据结构与算法分析(Mark Allen Weiss)
本书被世界众多大学用作教材,深入讨论算法和数据结构。8.5 算法导论(Thomas H. Cormen)
本书涵盖各类算法,旨在使不同层次的读者都能理解和接受。 通过阅读这些经典书籍,您将从C++的入门到进阶,全面提升编程技能,成为更加优秀的C++开发者。STL源码剖析9-set、multiset
STL源码深入研究:set与multiset的内部结构详解
1. 结论
在C++标准模板库(STL)中,set和multiset是两种常用的数据结构,它们底层实现依赖于红黑树(rb tree)。set是一种无序的关联容器,不允许有重复元素,而multiset则允许元素重复,但仍然保持插入顺序。
2. set的实现
set内部的红黑树使用了stl_function.h中的仿函数模板参数,这个仿函数用于定义元素的比较规则。set类在stl_set.h文件中定义,它通过这个仿函数确保了元素的唯一性,保证了查找、插入和删除操作的高效性。
3. multiset的特性
与set不同,multiset在stl_multiset.h中定义,它允许元素重复,这主要通过维护每个元素在树中的多个实例来实现。与set一样,它也依赖红黑树的数据结构,但对元素的比较规则更为宽松,允许基于给定的比较仿函数进行重复元素的插入和查找。
STL源码剖析总结笔记(5):认识迭代器的好帮手--list
在深入探讨STL中的`list`容器之前,我们先简要回顾了`vector`的特性以及分配器(`allocator`)的作用。接下来,我们将转向一个具有代表性的容器——`list`。之所以说其具有代表性,是因为`list`利用非连续的空间存储元素,从而在空间利用上更为精确。学习`list`是掌握迭代器机制的第一步。
“list”实质上是双向链表,它具有两个重要特性:前向指针和后向指针。在STL中,`list`节点的定义可能使用`_list_node*`(可能为了兼容性或设计规范)来指代节点结构,其中包含了指向下一个节点和上一个节点的指针。
`list`的内部实现为一个环状的双向链表结构,通过一个指向虚拟尾节点的指针`node`来方便遍历。`begin()`和`end()`方法的实现依赖于这个`node`。此外,`empty()`、`size()`、`front()`(访问头节点内容)、`back()`(访问尾节点内容)等方法的实现相对直截了当。
`list`的迭代器(`iterator`)设计得更为复杂,因为非连续的空间分配使得简单指针的操作无法直接使用。迭代器需要智能地追踪当前节点及其前后的节点,以便进行递增、递减和取值操作。这要求迭代器实现诸如`++`和`--`等操作符的重载,同时还需要定义至少1-5个`typedef`类型来支持迭代器的基本行为。
`++`操作符的重载遵循前置`++`和后置`++`的区别:前置`++`直接返回计算后的结果(即更新后的迭代器),而后置`++`返回迭代器的副本,避免了在C++中直接对整数进行两次后置`++`的操作,因为这会导致未定义的行为。`*`和`->`操作符用于访问当前节点的数据和成员,后者通过`*`操作符访问节点数据后再通过指针访问成员,确保了数据的安全访问。
`list`的基本操作主要依赖于节点指针的移动和修改,如插入、删除等。这些操作通常需要考虑双向链表的特性以及虚拟尾节点的存在,以避免丢失数据或产生无效指针。例如,`transfer()`方法是一个关键功能,允许将一段连续范围的元素移动到链表中的特定位置,这是许多其他复杂操作的基础。
在`list`中,`transfer()`方法实现了将`[first,last)`范围内的元素移动到指定位置的逻辑,通过调整节点的`next`和`prev`指针来完成移动,同时确保了数据的完整性。基于`transfer()`方法,其他高级操作也能够实现,尽管这些操作通常不直接暴露给用户,而是通过封装在`list`内部的实现来提供。
学习`list`不仅有助于理解迭代器的设计原理,也为探索其他容器(如`vector`和`deque`)的实现提供了基础。在接下来的内容中,我们将详细探讨迭代器的实现技巧,以及如何在实际编程中利用这些概念来优化代码。
2024-12-24 07:24
2024-12-24 07:22
2024-12-24 06:58
2024-12-24 06:44
2024-12-24 06:42