cpp STL、Standard Template Library
算法和数据结构,如向量、链表、队列、栈。
C++ 标准模板库的核心: 容器(Containers)、算法(Algorithms)、迭代器(iterators)、仿函数、内存配置器、配接器
Free C/C++ Libraries, Source Code and Frameworks(thefreecountry.com)
https://www.thefreecountry.com/sourcecode/cpp.shtml
Free Country 提供了免费的 C++ 源代码和 C++ 库,这些源代码和库涵盖了压缩、存档、游戏编程、标准模板库和 GUI 编程等 C++ 编程领域。
C/C++ Users Group
http://www.hal9k.com/cug/
C 和 C++ 的用户团体提供了免费的涵盖各种编程领域 C++ 项目的源代码,包括 AI、动画、编译器、数据库、调试、加密、游戏、图形、GUI、语言工具、系统编程等。
容器主要如下:
vector <T>:一种向量。
list <T>:一个双向链表容器,完成了标准 C++ 数据结构中链表的所有功能。
queue <T>:一种队列容器,完成了标准 C++ 数据结构中队列的所有功能。
stack <T>:一种栈容器,完成了标准 C++ 数据结构中栈的所有功能。
deque <T>:双端队列容器,完成了标准 C++ 数据结构中栈的所有功能。
priority_queue <T>:一种按值排序的队列容器。
set <T>:一种集合容器。
multiset <T>:一种允许出现重复元素的集合容器。
map <key, val>:一种关联数组容器。
multimap <key, val>:一种允许出现重复 key 值的关联数组容器。
部分算法如下:
for_each()find_if()count()count_if()replace()replace_if()copy()unique_copy()
sort()find()equal_range()merge()……
迭代器的诞生使算法和容器分离成为可能。算法是模板,其类型依赖于迭代器,不会局限于单一容器。
仿函数可以显著提高效率
struct three_mul{
bool operator() (int& v){
return (v%3 ==0)
}
}
STL教程:C++ STL快速入门
http://c.biancheng.net/stl/
string、basic_string、get_allocator返回配置器、resize 改变字符数量、replace替换字符、erase删除字符、max_size 最大可能个数一般是 232-1、assign赋值…
auto_ptr 智能指针
序列容器以线性序列的方式存储元素。它没有对元素进行排序,元素的顺序和存储它们的顺序相同。5 种标准的序列容器都具有不同的特性:
array<T,N>(数组容器):表示可以存储 N 个 T 类型的元素,是 C++ 本身提供的一种容器。此类容器一旦建立,其长度就是固定不变的,这意味着不能增加或删除元素,只能改变某个元素的值;
vector<T>(向量容器):用来存放 T 类型的元素,是一个长度可变的序列容器,即在存储空间不足时,会自动申请更多的内存。使用此容器,在尾部增加或删除元素的效率最高(时间复杂度为 O(1) 常数阶),在其它位置插入或删除元素效率较差(时间复杂度为 O(n) 线性阶,其中 n 为容器中元素的个数);
deque<T>(双端队列容器):和 vector 非常相似,区别在于使用该容器不仅尾部插入和删除元素高效,在头部插入或删除元素也同样高效,时间复杂度都是 O(1) 常数阶,但是在容器中某一位置处插入或删除元素,时间复杂度为 O(n) 线性阶;stack<T> 和 queue<T> 本质上也属于序列容器,基于deque实现。
list<T>(链表容器):是一个长度可变的、由 T 类型元素组成的序列,它以双向链表的形式组织元素,在这个序列的任何地方都可以高效地增加或删除元素(时间复杂度都为常数阶 O(1)),但访问容器中任意元素的速度要比前三种容器慢,这是因为 list<T> 必须从第一个元素或最后一个元素开始访问,需要沿着链表移动,直到到达想要的元素。
forward_list<T>(正向链表容器):和 list 容器非常类似,只不过它以单链表的形式组织元素,它内部的元素只能从第一个元素开始访问,是一类比链表容器快、更节省内存的容器。
array、vector、deque少见的函数:
shrink _to_fit()将内存减少到等于当前元素实际所使用的大小。
at()使用经过边界检査的索引访问元素
emplace()在指定的位置直接生成一个元素
emplace_back()在序列尾部生成一个元素,调用类型的构造函数
swap()交换两个容器的所有元素
data()返回指向容器中第一个元素的指针
fill()将所有元素设成给定值
list 和 forward_list 少见的函数:
before_begin()返回指向第一个元素前一个位置的迭代器
push_front()在序列的起始位置添加一个元素。
pop_front()移除序列头部的元素
cmplacc_front()在序列的起始位生成一个元索。
insert_after()在指定位置的后面插入一个或多个元素。
reverse()反转容器中某一段的元素。
erase()erase_after()remove()remove_if()…移除
unique()移除所有连续重复的元素
sort()对元素进行排序。
merge()合并两个有序容器。
splice()移动指定位置前面的所有元素到另一个同类型的 list 中。
splice_after()移动指定位置后面的所有元素到另一个同类型的 list 中。
advance() 前向迭代器移动多个位置
distance()得到元素的个数
自定义迭代器,iterator_traits
difference_type:两个 MyIterator 类型的迭代器之间差别值的类型。
value_type:MyIterator 类型的迭代器所指向值的类型。
pointer:Mylterator 类型的迭代器所表示的指针类型。
reference:来自于 *MyIterator 的引用类型。
iterator_category:前面介绍的迭代器类别的标签类类型:它们是 input_iterator_tag、output_iterator_tag、forward_iterator_tag、bidirectional_iterator_tag、random_access_iterator_tag。
容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。
这里有 3 种容器适配器:
stack<T>:是一个封装了 deque<T> 容器的适配器类模板,默认实现的是一个后入先出(Last-In-First-Out,LIFO)的压入栈。stack<T> 模板定义在头文件 stack 中。
queue<T>:是一个封装了 deque<T> 容器的适配器类模板,默认实现的是一个先入先出(First-In-First-Out,LIFO)的队列。可以为它指定一个符合确定条件的基础容器。queue<T> 模板定义在头文件 queue 中。
priority_queue<T>:是一个封装了 vector<T> 容器的适配器类模板,默认实现的是一个会对元素排序,从而保证最大元素总在队列最前面的队列。priority_queue<T> 模板定义在头文件 queue 中。
适配器类在基础序列容器的基础上实现了一些自己的操作,显然也可以添加一些自己的操作。它们提供的优势是简化了公共接口,而且提高了代码的可读性。
堆(heaps)不是容器,而是一种特别的数据组织方式。堆一般用来保存序列容器。
max_heap() 对随机访问迭代器指定的一段元素重新排列,生成一个堆。默认使用的是 < 运算符,可以生成一个大顶堆。
priority_queue 是一个堆。
push_heap() 来插入最后一个元素,为了保持堆的结构,这个元素会被重新排列到一个适当的位置。先用push_back() 插入,再用push_heap()排最后一个。
pop_heap()函数将第一个元素移到最后,并保证剩下的元素仍然是一个堆。然后就可以使用 vector 的成员函数 pop_back() 移除最后一个元素。
is_heap() 检查序列是否仍然是堆
is_heap_until() 函数返回一个迭代器,指向第一个不在堆内的元素。
sort_heap(),它会将元素段作为堆来排序。
智能指针
unique_ptr<T> 独占它所指向对象的所有权
shared_ptr<T> 允许多个指针指向同一个对象。
weak_ptr<T> 类型,它是一类从 shared_ptr<T> 生成的智能指针,可以避免使用 shared_ptrs<T> 带来的循环引用问题。
序列容器、优先级队列存储智能指针或一般指针,可提高效率。
map关联容器,key不可重复
pair<const K, T> 对象封装键及其关联的对象
tuple<> 模板是 pair 模板的泛化
multimap 容器保存的是有序的键/值对,但它可以保存重复的元素。
哈希是用给定范围的基本类型的数据项,或者用像 string 这样的对象,生成整数值的过程。
哈希算法有很多,但却没有可以通用的。
hash==k%m m通常是一个质数,因为它可以使哈希值更加均匀地分布在范围内。
hash== (a*k)%m m 通常选为 232。乘数 a 是和 m 相近的质数. 乘法哈希
std::hash<T>;生成类型T的哈希值
std::hash<std::string> hash_str;
hash_result = hash_str (“test str”);
unordered_map元素的位置由键的哈希值确定
std::unordered_map<std::string, size_t> people {
{
"Jan",44}, {
"Jim", 33}, {
"Joe", 99}}; // Name,age
unordered_map的键类型支持hash函数、==函数。
class Name
{
public:
size_t hash() const {
return std::hash<std::string>()(first+second); }
bool operator==(const Name& name) const {
return first == name.first && second== name.second; }
};
std::unordered_map<Name, size_t, Hash_Name, Name_Equal〉 people
std:: unordered_multimap<std::string,size_t> people {
{
"Jim",33}, {
"Joe",99}};
set (集合)
set<T> 容器保存 T 类型的对象,而且保存的对象是唯一的。其中保存的元素是有序的,默认用 less<T> 对象比较。可以用相等、不相等来判断对象是否相同。
multiSet<T> 容器和 set<T> 容器保存 T 类型对象的方式相同,但它可以保存重复的对象。
unorderd_set<T> 容器保存 T 类型的对象,而且对象是唯一的。元素在容器中的位置由元素的哈希值决定。默认用 equal_to<T> 对象来判断元素是否相等。
unordered_multiset<T> 容器保存 T 类型对象的方式和 unorderd_set<T> 相同,但它可以保存重复的对象。
set_union() 函数模板实现了集合的并集运算
set_intersection() 算法求交集
set_difference() 算法可以创建两个集合的差集
includes() 算法可以比较两个元素的集合
c++常用算法
sort()、stable_sort() 、partial_sort()、partial_sort_copy()…排序
nth_element() 也是排序,导致第 n 个元素被放置在适当的位置。
is_sorted() 是否有序
merge() 合并
inplace_merge() 合并同一个序列中两个连续有序的元素序列
find() 、find_if()、find_if_not() 、find_first_of() 、find_end() 查找
adjacent_find() 搜索序列中两个连续相等的元素
search() 、search_n() 查找
binary_search()二分查找
partition() 使给定谓词返回 true 的元素会被放在所有使谓词返回 false 的元素的前面
partition_copy() 使谓词返回 true 的元素会被复制到一个单独的序列中,使谓词返回 false 的那些元素会被复制到第三个序列中。这个操作不会改变原始序列。
partition_point() 找到序列的分区点
lower_bound() 算法可以在前两个参数指定的范围内查找不小于第三个参数的第一个元素
upper_bound() 算法会在前两个参数定义的范围内查找大于第三个参数的第一个元素
equal_range() 可以找出有序序列中所有和给定元素相等的元素。
all_of() 算法会返回 true,前提是序列中的所有元素都可以使谓词返回 true。
any_of() 算法会返回 true,前提是序列中的任意一个元素都可以使谓词返回 true。
none_of() 算法会返回 true,前提是序列中没有元素可以使谓词返回 true。
equal() 两个序列的长度相同,并且对应元素都相等
mismatch() 算法告诉我们两个序列是否匹配,如果不匹配,告诉我们不匹配的位置。
lexicographical_compare()算法可以比较由开始和结束迭代器定义的两个序列
next_permutation() 会生成一个序列的字典升序重排列
prev_permutation()降序的方式生成排列
is_permutation() 算法可以用来检查一个序列是不是另一个序列的排列
copy_n() 算法可以从源容器复制指定个数的元素到目的容器中。
copy_if() 算法可以从源序列复制使谓词返回 true 的元素
copy_backward() 会复制前两个迭代器参数指定的序列。第三个参数是目的序列的结束迭代器
reverse_copy() 算法可以将源序列复制到目的序列中,目的序列中的元素是逆序的
unique() 算法可以在序列中原地移除重复的元素
rotate() 算法旋转序列
rotate_copy() 算法会在新序列中生成一个序列的旋转副本,并保持原序列不变。
move() 算法会将它的前两个输入迭代器参数指定的序列移到第三个参数定义的目的序列的开始位置,第三个参数必须是输出迭代器。
swap_ranges() 算法来交换两个序列
4 种移除算法:
remove() 可以从它的前两个正向迭代器参数指定的序列中移除和第三个参数相等的对象。基本上每个元素都是通过用它后面的元素覆盖它来实现移除的。它会返回一个指向新的最后一个元素之后的位置的迭代器。
remove_copy() 可以将前两个正向迭代器参数指定的序列中的元素复制到第三个参数指定的目的序列中,并忽略和第 4 个参数相等的元素。它返回一个指向最后一个被复制到目的序列的元素的后一个位置的迭代器。序列不能是重叠的。
remove_if() 可以从前两个正向迭代器指定的序列中移除能够使作为第三个参数的谓词返回 true 的元素。
remove_copy_if() 可以将前两个正向迭代器参数指定的序列中,能够使作为第 4 个参数的谓词返回 true 的元素,复制到第三个参数指定的目的序列中。它返回一个指向最后一个被复制到目的序列的元素的后一个位置的迭代器。序列不能是重叠的。
fill() 和 fill_n() 算法提供了一种为元素序列填入给定值的简单方式
generate() generate_n()生成元素
transform() 可以将函数应用到序列的元素上,并将这个函数返回的值保存到另一个序列中
replace() 算法会用新的值来替换和给定值相匹配的元素
c++随机数、概率、分布、熵
随机数生成引擎是一个定义了生成随机位序列的无符号整数序列机制的类模板。
随机数生成器是随机数引擎类模板的一个预定义的实例。
随机数引擎适配器是一个类模板,它通过修改另一个随机数引擎生成的序列来生成随机数序列。
分布表示的是随机序列中的数出现在序列中的概率。STL定义了为各种不同的分布定义函数对象的类模板。
随机数的生成算法总是从单个或多个种子开始的,它们代表着产生随机数的计算的初始输入。种子决定了随机数生成器的初始状态和全部序列。对于给定的单个或多个种子,随机数生成器总会生成相同的序列。
随机数序列的熵取决于种子。对于 1 字节的种子,只有 255 个可能的值,所以最多可生成 255 个不同的序列。
random_device 类定义的函数对象可以生成用来作为种子的随机的无符号整数值。
std::random_device rd; // Source of seeds!
auto my_lst_seed = rd();
seed_seq 类是用来帮助设置随机数生成器的初始状态的。
默认随机数生成器是 std::default_random_engine
uniform_int_distribution 类模板定义了分布对象,它返回的是均勻分布在闭合范围 [a,b] 内的随机整
uniform_real_distribution 类模板定义了一个默认返回 double 型浮点值的连续分布。
generate_canonical() 函数模板会提供一个浮点值范围在 [0,1) 内,且有给定的随机比特数的标准均匀分布。
uniform_distribution 模板定义了可以产生随机浮点值的分布对象类型,默认是 double 类型。默认构造函数创建的是标准正态分布,因此期望是 0,方差是 1.0:
double mu {
50.0}, sigma {
10.0};
std::normal_distribution<> norm {
mu, sigma};//创建一个有特定值和标准差的正态分布
lognormal_distribution 模板的一个实例定义了一个默认返回浮点类型值的对数分布对象。 可定义期望、标准差 。
discrete_distribution 模板定义了返回随机整数的范围在 [0,n) 内的分布,基于每个从 0 到 n-1 的可能值的概率权重。
piecewise_constant_distribution 模板定义了一个在一组分段子区间生成浮点值的分布。
piecewise_linear_distribution 模板定义了浮点值的连续分布,它的概率密度函数是从一系列的样本值所定义的点得到的。每个样本值的权重都决定了它的概率密度值。
bernoulli_distribution 类定义了伯努利分布(t 参数为 1 的二项式分布)。
3 个引擎适配器模板是:
independent_bits_engine 适配器模板会将引擎生成的值修改为指定的比特个数。
discard_block_engine 适配器模板会将引擎生成的值修改为丢弃给定长度的值序列中的一些元素。
shuffle_order_engine 适配器模板会将引擎生成的值返回到不同的序列中。通过保存从引擎得到的给定长度的值序列来做到这些,然后在随机序列中返回它们。
linear_congruential_engine 类模板实现了一个最老且最简单的生成整数随机序列的算法,它被叫作线性同余法。unsigned int x = (a*seed + c) % m; 包含 3 个参数:乘数 a、增量 c 和模 m。
mersenne_twister_engine 类模板实现了梅森选择算法,它被这样叫是因为周期长度是一个梅森素数。梅森素数是 2n-1 形式的素数。
subtract_with_carry_engine 模板定义了实现带进位减法的随机数引擎,这是对线性同余算法的改进。
c++流迭代器,输入输出数据流的高效方法
istream_iterator 、ostream_iterator
fstream、string
istreambuf_iterator 模板定义了输入迭代器,ostreambuf_iterator 模板定义了输出迭代器。可以构造读写任意 char、 wchar_t、 char 16_t、char32 类型的字符的流缓冲区迭代器。
数值、时间、复数
numeric 头文件定义了使数值数据处理更简单或高效的 STL 功能。
chrono 头文件提供了处理时间的能力,包括时钟时间和时间间隔。
complex 头文件定义了支持复数处理的类模板。
iota() 函数模板会用连续的 T 类型值填充序列。
accumulate() 算法的基本版本,可以用 + 运算符求出元素序列的和。可以将 accumulate() 应用到 string 对象的序列上
inner_product() 算法可以计算两个 vector 的内积。
adjacent_difference() 算法可以算出输入序列中相邻元素对的差,并将它们保存到另一个序列中。
partial_sum() 可以计算输入序列中元素的部分和,并将结果保存到一个输出序列中。
valarray 类模板定义了保存和操作数值序列的对象的类型,主要用来处理整数和浮点数,但也能够用来保存类类型的对。
4 个可以应用到 valarray 对象的一元运算符:+、-、~ 和 !。效果是将运算符应用到数组的每个元素上,并返回一个新的 valarray 对象作为结果,不改变原对象。
所有的复合赋值运算符的左操作数都是 valarray 对象,右操作数是一个和所保存的元素同类型的值。在这种情况下,值会被合并到每个元素的值上,合并方式由运算符决定。右操作数也可以是和左操作数有相同元素个数和元素类型的 valarray 对象。复合算术赋值运算符 +=、-=、=、/=、%=。复合位操作赋值运算符 &=、|=、A=。复合移位赋值运算符 >>=、<<=。
算术运算符 +、-、、/、%;位操作运算符 &、|、^;位移运算符 >>、<<;逻辑运算符 &&、||;
3 个可以运用到序列的算法:
min_element():会返回一个指向输入序列的最小元素的迭代器;
max_element():会返回指向最大元素的迭代器;
minmax_element():会以 pair 对象的形式返回这两个迭代器。
duration (持续时间) 是定义为时间刻度数的时间间隔,可以指定一个时间刻度是多少秒。
complex< double > 类型的构造函数接受两个参数,第一个参数是实部的值,第二个部分是虚部的值。