【C++】STL(标准模板库)

1. 基本概念

  • STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称,现在已经成为C++标准库的重要组成部分。
  • STL的从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),容器和算法通过迭代器可以进行无缝地连接。
  • STL实现了数据结构和算法的分离
  • STL具有高可重用性、高性能和高移植性的特点。
    • 高可重用性:STL中几乎所有的代码都采用了类模板和函数模板的方式实现,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
    • 高性能:STL采用了高效的数据结构和算法。
    • 高移植性:STL是C++标准库的一部分,可以方便地跨项目、跨平台移植。

2. 容器

2.1. 容器的分类

  • 序列式容器
    • 每个元素都有固定位置,元素的位置取决于插入时机和地点,和元素值无关。
    • vector、deque、list、stack、queue
  • 关联式容器
    • 元素位置取决于容器特定的排序准则,和插入顺序无关。
    • set、multiset、map、multimap
  • 常用容器列表
    容器名描述头文件
    向量(vector)也称为动态数组,在内存中连续存储元素。它具有自动扩展大小的能力,支持随机访问和快速在末尾插入/删除元素。<vector>
    列表(list)也称为链表,由一系列节点链接而成。每个节点存储元素和指向下一个节点的引用。列表支持在任意位置插入/删除元素,但访问和搜索元素的性能较低。<list>
    双队列(deque)双向队列是一种特殊的队列,允许在两端进行插入和删除操作。它具有向量和列表的特性,可以高效地在队列的任一端添加或删除元素。<deque>
    集合(set)集合是一组唯一元素的容器,不允许重复。它提供了高效的搜索和插入操作,但不保持元素的顺序。<set>
    多重集合(multiset)多重集合类似于集合,但允许元素重复。<set>
    栈(stack)栈是一种后进先出(LIFO)的数据结构,类似于一堆盘子。元素只能从栈顶插入和删除。<stack>
    队列(queue)队列是一种先进先出(FIFO)的数据结构,类似于排队。元素只能从队列的一端插入,另一端删除。<queue>
    优先队列(priority_queue)优先队列是一种特殊的队列,元素按照优先级顺序进行插入和删除。具有最高优先级的元素始终排在队列的前面。<queue>
    映射(map)映射是一种键值对(Key-Value)的数据结构,每个键关联一个值。它提供了高效的键值查找,常见操作包括插入、删除和修改键值对。<map>
    多重映射(multimap)多重映射类似于映射,但允许多个键关联相同的值。<map>

2.2. vector

2.2.1. 构造vector对象

  • 默认构造
    vector<T> vec;	// T替换为要存储的数据的类型
    
  • 带参构造
    // 构造长度为n的vector对象
    vector<T> vec(n);
    
    // 构造长度为n、初始值为val的vector对象
    vector<T> vec(n, val);	
    
    // 用构造好的vector对象构造新的vector对象
    vector<T> vec1(n, val);
    vector<T> vec2(vec1);
    vector<T> vec2(vec1.begin(), vec1.end());
    
    // 用数组构造vector对象
    T arr[n] = {0};
    vector<T> vec(arr, arr + n);
    

2.2.2. vector的赋值

// 为vec2赋值
vector<T> vec1(n, val), vec2;
vec2.assign(vec1.begin(), vec1.end());
vec2.assign(n, val);
vec2 = vec1;

// 将vec1的元素和vec2的元素互换
vec2.swap(vec1);

2.2.3. vector的大小

// 获取容器的长度
vec1.size();

// 判断是否为空
vec1.empty();

// 如果容器变长,则以val填充;否则超出长度的元素将被删除
vec1.resize(num, val);

2.2.4. vector元素的访问

// 如果越界,运行出错
vec1[1];

// 如果越界,抛出异常
vec1.at(1);

2.2.5. vector元素的插入与删除

// 在前端插入元素
vec1.front() = 2;

// 在末端插入元素
vec1.back() = 3;
vec1.push_back(3);

// 在末端删除元素
vec1.pop_back();

// 在任意位置插入元素
vec1.insert(vec1.begin() + 2, 3);	// 在第3个元素所在位置
vec1.insert(vec1.begin() + 2, 2, 3); // 插入2个3组成的序列
vec1.insert(vec1.begin() + 2, vec1.begin(), vec1.end());//插入指定位置的数据

// 删除任意位置的元素
vec1.erase(vec1.begin() + 2);

2.2.6. vector中迭代器的使用

vector<T> vec1(n, val);
vector<T>::iterator it;	// 创建迭代器
it = vec1.begin();	// 指向第一个元素的正向迭代器
it = vec1.end();	// 指向最后一个元素后一个位置的正向迭代器

vector<T>::reverse_iterator rit;	// 创建反向迭代器
rit = vec1.rbegin();	// 指向最后一个元素的反向迭代器
rit = vec1.rend();	// 返回指向第一个元素之前一个位置的反向迭代器

vector<T>::const_iterator cit;	// 创建常量迭代器,不能修改元素
cit = vec1.cbegin();// 指向第一个元素的常量正向迭代器
cit = vec1.cend();	// 指向最后一个元素后一个位置的常量正向迭代器

vector<int>::const_reverse_iterator  crit;	// 创建常量反向迭代器
crit = vec1.crbegin();// 指向最后一个元素的常量反向迭代器
crit = vec1.crend();	// 返回指向第一个元素之前一个位置的常量反向迭代器

// 迭代器增减
it = it + 2;
it = it - 2;
it++;
it--;

// 迭代器比较
it == it + 2;	// false
it != it + 2;	// true

// 迭代器取值
*it;

2.3. deque

  • deque(double-ended queue,双端队列)是双端数组,而vector是单端的。
  • 头部和尾部添加或移除元素都非常快速,但是在中部插入元素或移除元素比较费时。
  • deque与vector的接口十分相似,主要多了两个函数。
    • push_front():在前端添加元素。
    • pop_front():删除前端元素。

2.4. list

  • list是一个双向链表容器,可高效地进行插入删除元素
  • list不可以随机存取元素,不支持索引访问元素
  • list的使用
// 构造、赋值、大小、首末元素、插入与vector相同

// 在头尾添加移除元素
ls.push_back(elem);
ls.pop_back();
ls.push_front(elem);
ls.pop_front();

// 删除
ls.clear();	// 删除所有元素
ls.remove(elem); //删除与elem匹配的元素
// ls.erase与vector相同

// 反转,改动原值
ls.reverse();

2.5. stack

  • stack是堆栈容器,是一种“先进后出(FILO)”的容器。
  • stack的使用
// 构造、赋值、大小与vector相同

// 入栈
s.push(elem);

// 出栈
s.pop();

// 获取栈顶元素
s.top();

// 遍历栈中元素并清空栈
while(!s.empty()){
	cout << s.top() << endl;
	s.pop();
}

2.6. queue

  • queue是队列容器,是一种“先进先出(FIFO)”的容器。
  • queue的使用
// 构造、赋值、迭代、大小、首尾元素与vector相同

// 入队
q.push(elem);

// 出队
q.pop();

2.7. set/multiset

  • set是一个集合容器,其中所包含的元素是唯一的(因此可用于去重),集合中的元素按一定的顺序排列(默认升序排序)。元素插入过程是按排序规则插入,所以不能指定插入位置。
  • set采用红黑树变体的数据结构实现,红黑树属于平衡二叉树。在插入操作和删除操作上比vector快
  • set 不可以直接索引元素
  • multiset与set的区别:set支持唯一键值,每个元素值只能出现一次;而multiset中同一值可以出现多次
  • 不可以直接修改set或multiset容器中的元素值,因为该类容器是自动排序的。如果希望修改一个元素值,必须先删除原有的元素,再插入新的元素。
  • set/multiset的使用
// 构造、赋值、大小、迭代与vector相同

// 添加元素
s.insert(elem);

// 删除元素,存在返回值表示是否删除成功的重载
s.erase(elem);

// 用仿函数指定排序规则
class Less{
	bool operator()(const int& left, const int& right) const
	{
		return left > right;	// 降序排列
	}
}
set<int, Less> s;

// 查找,返回指向elem的迭代器
it = s.find(elem);

// 统计elem元素的个数,用于multiset
s.count(elem);

// 返回第一个<=elem元素的迭代器
s.lower_bound(elem);

// 返回第一个>=elem元素的迭代器
s.upper_bound(elem);

// 返回第一个<=elem元素的迭代器和第一个>=elem元素的迭代器的对组
pair<T1, T2> p = s.equal_range(elem);
p.first;	// 对组第一个元素
p.second;	// 对组第二个元素

2.8. map/multimap

  • map是一个映射容器,能将两个元素通过键值对的形式关联起来。
  • multimap允许多个键关联相同的值。
  • map的使用
// 插入
m.insert(pair(key,value));
m.insert(map<T1, T2>::value_type(key, value));
m[key] = value;	// 如果键存在,则修改原值;实质是先删除再插入

// 迭代器取键值
it->first;	// 取键
it->second;	// 取值

// 访问元素
m[key];
m.at(key);
it = m.find(key);

3. 迭代器

  • 迭代器是一种检查容器内元素并且遍历容器内元素的数据类型
  • 选代器提供对一个容器中的对象的访问方法并且定义了容器中对象的范围
  • 通过迭代器统一了对STL所有容器的访问方式
  • 删除或插入元素将导致正在使用的迭代器失效,可以接收插入或删除函数的返回值更新迭代器
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值