STL(Standard Template Library,标准模板库),是惠普实验室开发的一系列软件的统称。现在主要出现在 c++中,但是在引入 c++之前该技术已经存在很长时间了。ttps://blog.csdn.net/weixin
C++ STL(Standard Template Library,标准模板库)是一套强大的C++模板类集合,它提供了许多高效的数据结构和算法。
STL的核心包括三个组成部分:
容器(Containers):用于存储数据的对象,例如vector、list、deque和map。容器是用来管理对象集合的工具,可以容纳不同类型的数据,并且支持对其内容进行添加、删除和访问等操作。
算法(Algorithms):作用于容器上的通用函数,提供了一系列标准化的操作方式,如对容器内容执行初始化、排序、搜索和转换等操作。
迭代器(Iterators):用于遍历容器中的元素。迭代器提供了一种通用的接口来访问容器内的元素,使得算法能够以统一的方式处理不同的容器类型。
其中容器:
STL中常用的容器包括vector、list、deque、set、map、unordered_set和unordered_map等。具体如下:
vector:
它是一个动态数组,支持随机访问,适合在末尾快速添加或删除元素。由于其连续的内存布局,它也适合进行快速的迭代操作。
特性:
- vector特别擅长在尾部进行插入和删除操作,这些操作的时间复杂度为O(1)。在容器的头部或中部进行插入或删除操作时,时间复杂度则为线性阶O(n),因为需要移动元素来维护连续内存布局。
创建方法:
- 创建一个空的vector容器,如vector<double> values;当添加第一个元素时,vector会自动分配内存。
- 指定初始值及元素个数,如vector<int> primes {2, 3, 5, 7, 11, 13, 17, 19};,这样创建了一个含有8个素数的vector容器。
- 也可以只指定元素个数,如vector<double> values(20);,这会创建一个有20个元素的vector,默认初始值为0。
- 通过其他同类型容器来创建新的vector,如使用数组初始化std::vector<int> values(array, array+2);
- 添加元素的方法:push_back()和emplace_back()是两种常用的添加元素到vector尾部的方法。其中,emplace_back()直接在容器末尾构造元素,避免了额外的拷贝或移动操作,通常更高效。
此外,vector支持多种操作,如访问元素、修改元素、排序、反转等。例如,使用v[index]可以访问vector中特定位置的元素,而v.size()则可以获取当前vector的大小。
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v1;//构造一个空的vector
cout << "容量为:"<<v1.capacity() << " 元素个数: " << v1.size() << endl;
vector<int> v2(5);//构造一个空间大小为5,并且元素为5个(有默认值)的vector
cout << "容量为:" << v2.capacity() << " 元素个数: " << v2.size() <<" v2[0]:"<<v2[0]<< endl;
vector<int> v3(5,111);//构造一个空间大小为5,并且元素为5个(每个元素初始值为111)的vector
cout << "容量为:" << v3.capacity() << " 元素个数: " << v3.size() << " v3[0]:" << v3[0] << endl;
vector<int> v4(v3);//拷贝构造vector
cout << "容量为:" << v4.capacity() << " 元素个数: " << v4.size() << " v4[0]:" << v4[0] << endl;
for (size_t i = 0; i < v2.size(); i++)
{
//cout << v2[i] << " ";
//cout << v2.at(i)<< " ";
cout << &v2[i] << " ";//输出地址,说明存储空间是连续的
}
cout << endl;
return 0;
}
//capacity
函数用于查询容器的容量,即它能够存储的元素数量。
在C++中,capacity
函数通常与vector
容器相关联,因为vector
在内存中连续存储元素,并且可以预分配一块内存空间来提高性能。对于其他类型的容器,如list
、map
、set
等,由于它们的元素在内存中散布,不预分配内存,所以这些容器没有capacity
成员函数。
具体到vector
容器,capacity
指的是容器在不重新分配内存的情况下能够存储的元素数量。这与size
不同,size
是指容器实际存储的元素数量。当vector
需要增长以容纳更多元素时,它的容量通常会增加,以避免频繁的内存重新分配操作。具体的增长策略可能因编译器而异,但通常是增加到原容量的1.5倍或者翻倍。
此外,可以通过构造函数指定vector
的初始容量,例如使用vector(n, value=T())
构造函数,其中n
是指定的容量,value
是元素的初始值。如果不指定容量,那么vector
的默认容量取决于实现,例如对于std::string
类型的vector
,默认容量可能是15。
list:
它是一个双向链表,支持在任何位置高效地插入或删除元素,但不支持随机访问
list容器的基本概念是它以双向链表的形式实现,这意味着它的元素可以分散存储在内存空间中,而不是必须存储在一整块连续的内存空间里。这种结构使得list在插入和删除操作上具有优势,尤其是在链表的中间位置进行操作时,因为这些操作不需要移动其他元素,只需要改变指针的指向即可。
list容器的特点包括:
- 插入和删除操作:由于list是基于链表的,它可以在常数时间内完成在头部或尾部的插入和删除操作。而在中间位置的插入和删除也非常高效,因为只需要修改相邻元素的指针即可。
- 访问操作:虽然list不支持随机访问,但提供了双向遍历的能力,可以通过迭代器进行顺序或逆向访问。
- 内存分配:list的元素在内存中是非连续存储的,每个元素都是一个节点,包含数据和指向前后元素的指针。
- 成员函数:list提供了一系列成员函数来操作元素,如push_front()、push_back()、pop_front()、pop_back()等,这些函数允许在list的不同位置添加或移除元素
deque :
它是一个双端队列,支持在两端快速添加或删除元素,同时支持随机访问,适合需要从两端操作数据的场景。
deque(双端队列)是一种线性容器,它允许在两端快速地插入和删除元素。与vector不同,deque的内部结构被设计为分段连续的内存空间,这使得在两端进行操作时不需要移动其他元素,从而保持了高效的性能。以下是deque的一些详细用法:
- 创建deque容器:可以通过多种方式创建deque容器。例如,创建一个空的deque容器,可以直接声明一个没有元素的deque对象,如std::deque<int> d;这样的容器在创建后可以进行添加或删除元素的操作。
- 头尾操作:由于deque是双向开口的,它可以在头部和尾部进行高效的插入和删除操作。这对于需要在这些位置频繁操作的数据结构来说是非常有用的。
- 中间操作:虽然deque在头部和尾部的操作效率很高,但在中间部分插入元素会比较费时,因为这需要移动其他元素来腾出空间。
头文件:使用deque之前,需要包含相应的头文件#include <deque>,并且因为它属于std命名域,所以通常需要使用using std::deque;来简化代码。
总的来说,deque容器特别适合那些需要在两端进行频繁操作的场景,如实现一个先进先出(FIFO)的数据结构或者模拟队列的行为。在选择使用deque时,应考虑到其特点和优势,以便更有效地处理特定的数据操作需求。
set:
它是一个集合,内部元素按特定顺序排列,适合快速查找元素。它不允许存储重复的元素,适用于需要去重和有序存储的场合。
set容器是一种关联式容器,它能够存储一组元素并自动保证它们按照一定的次序排列。
首先,需要包含相应的头文件#include <set>,并使用std::set来定义一个集合。set容器可以存储各种类型的数据,包括基本数据类型、结构体、类对象等。
创建set容器的方法有以下几种:
- 默认构造函数:通过调用默认构造函数创建一个空的set容器。例如,std::set<std::string> myset; 这将创建一个空的set容器,其中的元素会按照默认的升序排序规则(std::less<T>)进行排序。
- 初始化构造函数:在创建set容器的同时进行初始化。例如,std::set<int> s(s1); 这将用另一个集合s1来初始化新创建的集合s。
- 范围构造函数:使用迭代器的范围来初始化集合。例如,std::set<int> s(b, e); 这里b和e是迭代器的开始和结束标记。
此外,set容器还支持赋值操作和大小操作。赋值操作可以通过重载等号操作符实现,例如set& operator= (const set &st);。大小操作包括返回容器中元素的数目的size()函数和判断容器是否为空的empty()函数。
map:
它是一个映射,允许通过键来快速访问对应的值。内部元素按键的顺序排列,适合构建快速查找的键值对集合。
map容器是一种关联式容器,它允许用户存储键值对,并且能够高效地进行查找和排序操作。
首先,使用map之前需要包含相应的头文件#include <map>,并且为了方便使用,通常还需要添加using namespace std;。这样,就可以在代码中定义和操作map了。
接下来是一些关于map的基本用法:
- 声明map变量:可以声明一个map类型的变量,例如std::map<std::string, int> myMap;,这将创建一个空的map,其中键是字符串类型,值是整数类型。
- 插入元素:向map中插入元素可以使用insert()函数或者通过下标操作符[]。例如,myMap.insert(std::make_pair("apple", 1));或myMap["apple"] = 1;都会将键值对("apple", 1)添加到map中。
- 查找元素:可以通过键来查找对应的值,如果键存在于map中,下标操作符会返回对应的值,否则会插入一个新的键值对。例如,int value = myMap["apple"];会查找键为"apple"的值。
- 删除元素:可以使用erase()函数来删除指定的键值对,例如myMap.erase("apple");会删除键为"apple"的元素。
- 清空map:使用clear()函数可以清空map中的所有元素,例如myMap.clear();会移除所有键值对。
unordered_set :
它是一个无序集合,与set相似,但不保证元素的顺序,因此查找速度通常更快。
unordered_map:
它是一个无序映射,与map相似,但不保证键的顺序,因此根据键查找值的速度通常更快。