Interview_C++_day7

map 和 set

\(map\) 是映射,\(set\) 是集合,都是通过红黑树来实现的。他们的操作行为,都是转调红黑树的操作行为。

  1. \(map\) 中元素为 (键-值)key-value,关键字起到索引作用,值保存相关数据。\(set\) 元素为 (键)key,值即是键,
  2. \(map\) 允许修改 \(value\),不允许修改 \(key\)\(set\) 的迭代器是 \(const\) 的,不允许修改元素。原因: \(map\)\(set\) 是通过关键字排序来实现有序的,如果要修改,需要删除原本键值,在插入新的键值,每次操作后都需要重新调节平衡,这样破坏了原本的结构,使得迭代器失效,不知道指向改变前的还是改变后的位置。
  3. \(map\) 支持下标操作,\(set\) 不支持。\(map\) 下标操作 \([key]\) ,是通过关键字 \(key\) 去查找,返回该关键字的值,若该关键字不存在,则会插入一个具有该关键字和 \(value\) 类型默认值到 \(map\) 中。

map 和 unordered_map

map unordered_map
通过红黑树实现 通过 \(hash\) 表实现
操作复杂度 \(log\) 级别 操作复杂度常数级别
内部有序 内部无序
适用于对顺序有要求的场景 适用于频繁查找的场景

\(unordered\_map\) 基于 \(hash\) 表,需要用 \(vector\) 来解决冲突,所以查找和存储的时间大大减少,而代价是花费更多内存。

STL 的组成

\(STL\) 由六部分组成:算法、容器、迭代器、仿函数、适配器、内存分配器。

  1. 通过迭代器,可以实现对容器内容的读和写。
  2. 对于重载了 \(()\) 的类,可以实现类似函数调用过程,叫做仿函数。
  3. 适配器将一个类的接口适配成用户指定的形式,使原本不兼容的类可以一起工作。
  4. 内存分配器负责空间的配置和管理。

容器和容器适配器

容器适配器是对容器的一种再封装,容器适配器不支持迭代。

\(STL\) 自带的容器有 \(vector、list、map、set、deque\),同时还提供了一些特别的容器适配器,比如 \(stack、queue、priority\_queue\)

区别在于 \(stack、queue\) 的底层实现用到了 \(deque\)\(priority\_queue\) 的底层实现用到了 \(vector\),而 \(vector\) 的底层实现没有用到别的容器。

vector 和 list

  • \(vector\) 存在扩容机制:
    在向 \(vector\) 添加元素时,如果还有剩余的空间,那么会直接添加到指定位置,如果没有剩余的空间,那么会重新开辟原本容器的两倍空间,然后将旧的数据复制到新开辟的空间,释放旧内存。
vector list
类型 动态数组 动态链表
底层实现 数组实现 双向链表实现
访问 支持随机访问,\(O(1)\) 不支持随机访问,\(O(n)\)
插入 在末尾 \(O(1)\),在中间 \(O(n)\) 很快,\(O(1)\)
删除 在末尾 \(O(1)\),在中间 \(O(n)\) 很快,\(O(1)\)
内存来源 从堆区分配空间 从堆区分配空间
内存使用 \(vector\) 是顺序内存 \(list\) 不是顺序内存
内存分配 \(vector\) 一次性分配好,不够时扩容 \(list\) 每次插入节点都需要进行内存申请
性能 \(vector\) 访问性能好,插入删除性能差 \(list\) 插入删除性能好,访问性能差
适用场景 经常随机访问,不在乎插入和删除效率 经常插入删除,不在乎访问效率

STL 中 resize 和 reserve

\(resize()\) 改变当前容器内含有元素的数量。例如 \(vectorg\) 操作 \(g.resize(n)\),则容器新增 \(n-g.size()\) 个元素或删除末尾多出的元素。

\(reserve()\) 改变当前容器可存放元素的最大容量,例如操作 \(g.reserve(n)\),如果 \(n\) 值大于当前容器容量 \(g.capacity()\),则会重新分配一块能存 \(n\) 个对象的空间,然后把容器内元素复制过来并销毁之前的内存,否则不会发生变化。

迭代器和指针

迭代器就是把不同集合类的访问逻辑抽象出来,使得不用暴露集合内部结构而达到遍历集合的效果。

迭代器不是指针,是类模板。迭代器只是模拟出指针的一些功能,本质是封装了原生指针,提供了比指针更高级的行为。迭代器返回的是对象的引用,而不是对象的值。

你可能感兴趣的:(Interview_C++_day7)