IO、容器、泛型算法和动态内存

来源:互联网 发布:ip网络广播功放终端 编辑:程序博客网 时间:2024/06/10 15:28

前言

最近刚刚开题答辩,现在需要重新投入到战斗中来。

C++标准库是一类强大的数据结构和算法的集合。利用C++泛型的能力,使得一些数据结构和算法得以方便的使用。C++标准库内容很多,我也只打算按照C++primer的顺序,复习其中的IO、容器、泛型算法以及动态内存。这些都是轮子,可以直接拿来用。但是有必要好好阅读和理解其中的源代码,对于我们来说将是很大的提升。

往往在刷题过程中,都需要用到很多数据结构。合理使用它们是一个课题。

本文从IO开始说起,会将大部分有用的知识点写出来。自己能够复习的前提下,把c++基础打扎实。

IO库

IO是计算机一个重要的组成部分。

IO类型

  • iostream 从流中读写数据
  • fstream 从文件中读写数据
  • sstream 从string中读写数据

IO对象无拷贝或赋值。另外读写io对象会改变其状态,因此通过引用传参不能是const的。

顺序容器

顺序容器提供一个顺序访问集合对象的能力,这个顺序不依赖于元素的值,而与元素加入容器的顺序相对应。

顺序容器类型:

  • vector:可变大小数组,快速随机访问,在尾部之外插入和删除可能很慢
  • deque:双端队列,支持快速随机访问,在头尾插入和删除很快
  • list:双向链表,只支持双向顺序访问,在任何位置插入和删除都很快
  • forward_list:单向链表,只支持单向顺序访问,在任何位置插入和删除都很快
  • array:固定大小数组,支持快速随机访问,不能添加和删除元素
  • string:与vector类似的容器,但专门用于保存字符。尾部也可以高效的插入和删除

顺序容易比较常用的操作,我就省略了,这些需要在平时刷题和练习当中使用,才能快速掌握。简单的罗列用处不大。

1.vector是如何增长的

因为vector是很多容器的基础,明白vector的存储策略非常必要。首先,需要明白的是,vector在内存中是连续存储的。这样,当当前无法存储更多的元素时,需要申请新的空间,并且将旧的元素复制到新的存储空间里。为了不频繁的做这样一个操作,容器都会预留一部分作为备用。capacity方法获得就是vector申请空间的大小,而size方法获得是实际存储元素的大小。一般来说,预留空间是空间的一倍。

2.string一些常用的操作

// 数值转换int i = 42;string s = to_string(i); // 内置算数类型转stringdouble d = stod(s); // string转doubleint j = stoi(s); // string转intlong long a = stoll(s); // string转long longfloat c = stof(s); // string转float

泛型算法

泛型算法独立于容器和类型存在。大多数算法定义在algorithm头文件里。需要比较清楚的是,这些算法一般不直接操作容器,而是遍历两个头尾迭代器或指针来指定范围。

  • 查找
int val = 42;auto result = find(vec.cbegin(), vec.cend(), val);cout << resul == vec.cend() ? "is not present" : "is present";
  • 累积和
int sum = accumulate(vec.begin(), vec.end(), 0);
  • 排序
// 仿函数的写法struct cmp{    bool operate() (const int &a, const int &b) {        return a < b;    }}sort(vec.begin(), vec.end(), cmp());sort(vec.begin(), vec.end(), less<int>()); // 从小到大排序sort(vec.begin(), vec.end(), greater<int>()); // 从大到小排序priority_queue<int, vector<int>, less<int> > p_q; // 最大堆priority_queue<int, vector<int>, greater<int> > p_q; // 最小堆
  • lambda 表达式

lambda 表达式是C++中一种可调用对象,另外还有(函数、函数指针、类)。
表示一个可调用的代码单元(可理解成一个内联函数)。结构是:

[capture list](param list) -> return type {func body};// 捕获列表表示lambda表达式计算需要使用的函数内的变量
  1. lambda必须使用尾置返回,默认返回void
  2. lambda必须要有捕获列表和函数体
  3. lambda没有默认参数
auto f = [] {return 42;};cout << f();stable_sort(vec.begin(), vec.end(),     [](const int &a, const int &b)    { return a < b;});

编译器在处理lambda表达式时,会生成一个lambda对应的未命名对象。对象中的数据成员通过初始化捕获列表得到。类似于参数传递。

  1. 值捕获
  2. 引用捕获
  3. 隐式捕获([=]或者[&]

关联容器

关联容器和顺序容器有很大的不同。关联容器可以说是一种映射,通过关键字来保存和访问元素。

关联容器类型:

1.按关键字有序保存元素, 可遍历

  • map : 关联数组,关键字-值对
  • set : 关键字即值,只保存关键字
  • multimap :关键字可重复的map
  • multiset : 关键字可重复的set

2.无序集合, 不可遍历

  • unordered_map : 用哈希函数组织的map
  • unordered_set : 用哈希函数组织的set
  • unordered_multimap : 哈希组织的map,关键字可重复
  • unordered_multiset : 哈希组织的set, 关键字可重复
map<int, int> a;a.find(1) == a.end(); // 找下标set<int> a;a.find(1); // 两种都可以,find返回的是迭代器a.count(1);// 添加a.insert({1, 1});a.insert(1);// 删除a.erase(1);// 注意使用下标访问map时,如果不存在,会添加一个,并初始化

pair类型

pair<string, int> a("1", 2);make_pair("1", 2);a = {"1", 2};a.first;a.second;

动态内存

C++需要自己控制内存释放,这一点非常重要。因此会写一篇专门讨论C++中的内存申请以及释放的博客,敬请期待。