最近在刷leetcode的时候,经常要用到标准库,这里总结一下标准库的常见用法,用于查询使用。
queue
queue模板类的定义在<queue>
头文件中。只能在容器的末尾添加新元素,只能从头部移除元素。
与stack模板类很相似,queue模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型。
定义queue对象的示例代码如下:
1 | queue<int> q1; |
queue的基本操作有:
- 入队,如
q.push(x);
将x接到队列的末端 - 出队,如
q.pop();
弹出队列的第一个元素,注意,并不会返回被弹出元素的值 - 访问队首元素,如
q.front();
即最早被压入队列的元素 - 访问队尾元素,如
q.back();
即最后被压入队列的元素 - 判断队列空,如
q.empty();
当队列空时,返回true - 访问队列中的元素个数,如
q.size();
vector
vector模板类的定义在<vector>
头文件中。
定义vector对象的示例代码如下:
1 | vector<int> v1; |
vector的基本操作有:
尾部插入数字:
vec.push_back(a);
使用下标访问元素:
cout<<vec[0]<<endl;
记住下标是从0开始的。使用迭代器访问元素:
1
2
3vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;插入元素:
vec.insert(vec.begin()+i,a);
在第i
个元素后面插入a
;删除元素:
vec.erase(vec.begin()+2);
删除第3个元素;vec.erase(vec.begin()+i,vec.end()+j);
删除区间[i,j-1];
区间从0开始vec.pop_back();
删除最后一个元素向量大小:
vec.size();
得到首元素:
vec[0];
或者vec.front();
得到最后一个元素:
vec[vec.size() - 1];
或者vec.back();
清空:
vec.clear()
//清空之后,vec.size()
为0反转:
reverse(vec.begin(), vec.end());
stack
stack模板类的定义在<stack>
头文件中。
定义stack对象的示例代码如下:
1 | stack<int> s1; |
stack的基本操作有:
top()
:返回一个栈顶元素的引用,类型为T&
。如果栈为空,返回值未定义。push(const T& obj)
:可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。push(T&& obj)
:以移动对象的方式将对象压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。pop()
:弹出栈顶元素。size()
:返回栈中元素的个数。empty()
:在栈中没有元素的情况下返回 true。emplace()
:用传入的参数调用构造函数,在栈顶生成对象。swap(stack<T> & other_stack)
:将当前栈中的元素和参数中的元素交换。参数所包含元素的类型必须和当前栈的相同。对于 stack 对象有一个特例化的全局函数 swap() 可以使用。
map
map是一类关联式容器。提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力。
它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。
map定义在<map>
头文件中。注意,STL头文件没有扩展名.h
定义map示例:
1 | map<string, int>mapstring; map<int, string >mapint; |
插入数据:
1 | map<int, string> maplive; |
map中元素的查找: find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
1 | map<int, string >::iterator l_it;; |
map中元素的查找:count()函数,返回值为0或1,表示是否包含。
1 | if(m.count(key)>0) |
map中元素的删除:如果删除112;
1 | map<int, string >::iterator l_it;; |
map的基本操作函数:
1 | C++ Maps是一种关联式容器,包含“关键字/值”对 |
deque
deque(双端队列)是由一段一段的定量连续空间构成,可以向两端发展,因此不论在尾部或头部安插元素都十分迅速。 在中间部分安插元素则比较费时,因为必须移动其它元素。
deque定义在头文件deque
中。
定义deque如下:
1 | deque<int> a; // 定义一个int类型的双端队列a |
容量函数:
1 | 容器大小:deq.size(); |
添加函数:
1 | 头部添加元素:deq.push_front(const T& x); |
删除函数:
1 | 头部删除元素:deq.pop_front(); |
访问函数:
1 | 下标访问:deq[1]; // 并不会检查是否越界 |
可以看到,deque 与 vector 的用法基本一致,除了以下几处不同:
- deque 没有 capacity() 函数,而 vector 有;
- deque 有 push_front() 和 pop_front() 函数,而 vector 没有;
- deque 没有 data() 函数,而 vector 有。
priority_queue
priority_queue 容器适配器定义了一个元素有序排列的队列。默认队列头部的元素优先级最高。因为它是一个队列,所以只能访问第一个元素,这也意味着优先级最高的元素总是第一个被处理。
priority_queue 模板有 3 个参数,其中两个有默认的参数;第一个参数是存储对象的类型,第二个参数是存储元素的底层容器,第三个参数是函数对象,它定义了一个用来决定元素顺序的断言。因此模板类型是:
1 | template <typename T, typename Container=std::vector<T>, typename Compare=std::less<T>> class priority_queue |
priority_queue 实例默认有一个 vector 容器。函数对象类型 less<T>
是一个默认的排序断言(最大堆),最大的元素排在队列前面,出队的时候会出最大的元素,而入队的时候会重排,定义在头文件 function 中,决定了容器中最大的元素会排在队列前面。fonction 中定义了 greater<T>
,用来作为模板的最后一个参数对元素排序,最小元素会排在队列前面,出队的时候最小的元素先出队,而入队的时候会重排。当然,如果指定模板的最巵一个参数,就必须提供另外的两个模板类型参数。
可以如下所示生成一个空的优先级队列:
1 | std::priority_queue<std::string> words; |
可以用适当类型的对象初始化一个优先级队列:
1 | std::string wrds[] { "one", "two", "three", "four"}; |
对 priority_queue 进行操作有一些限制:
push(const T& obj)
:将obj的副本放到容器的适当位置,这通常会包含一个排序操作。push(T&& obj)
:将obj放到容器的适当位置,这通常会包含一个排序操作。emplace(T constructor a rgs...)
:通过调用传入参数的构造函数,在序列的适当位置构造一个T对象。为了维持优先顺序,通常需要一个排序操作。top()
:返回优先级队列中第一个元素的引用。pop()
:移除第一个元素。size()
:返回队列中元素的个数。empty()
:如果队列为空的话,返回true。swap(priority_queue<T>& other)
:和参数的元素进行交换,所包含对象的类型必须相同。
set
在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。
添加元素
下面是一个使用 insert() 的示例:
1 | std::set<string, std::greater<string>> words {"one", "two", "three"}; |
插入单个元素会返回一个 pair<iterator,bool>
对象。插入单个元素和一个标识,会返回一个迭代器。插入一段元素或一个初始化列表就不会有返回值。当 insert() 的参数是初始化列表时,会用列表中的字符串创建 string 对象。下面是两个在 set 容器中创建元素的示例:
1 | std::set<std::pair<string,string>> names; |
这和 map 一样。成员函数 emplace() 会返回一个 pair
删除元素
成员函数 clear() 会删除 set 的所有元素。成员函数 erase() 会删除迭代器指定位置的元素或与对象匹配的元素。例如:
1 | std::set<int> numbers {2, 4, 6, 8, 10, 12, 14}; |
成员函数 erase() 可以删除一段元素:
1 | std::set<int> numbers {2, 4, 6, 8, 10, 12, 14}; |
如果 set 没有元素,成员函数 empty() 返回 true,成员函数 size() 返回它所包含的元素个数。如果担心无法在 set 中存储尽可能多的元素,可以调用成员函数 max_size() 来得到可存储的最大元素个数,这显然会是一个很大的值。
访问元素
set 的成员函数 find() 会返回一个和参数匹配的元素的迭代器。如果对象不在 set 中,会返回一个结束迭代器。例如:
1 | std::set<string> words {"one", "two","three", "four","five"}; |
调用成员函数 count()
可以返回指定键所对应的元素个数,返回值通常是 0 或 1,因为 set 容器中的元素是唯一的。set 容器模板定义了成员函数 equal_range()、lower_bound()、 upper_bound(),这和 multiset 容器在很大程度上是一致的。
迭代器
这个知识点不应该放在这里,但是我想把这篇文章当成是刷LeetCode时的查阅语法的地方,所以就姑且放在这里吧。
要访问顺序容器和关联容器中的元素,需要通过“迭代器(iterator)”进行。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。
迭代器按照定义方式分成以下四种。
1) 正向迭代器,定义方法:容器类名::iterator 迭代器名;
2) 常量正向迭代器,定义方法:容器类名::const_iterator 迭代器名;
3) 反向迭代器,定义方法:容器类名::reverse_iterator 迭代器名;
4) 常量反向迭代器,定义方法:容器类名::const_reverse_iterator 迭代器名;
通过迭代器可以读取它指向的元素,*迭代器名
就表示迭代器指向的元素。通过非常量迭代器还能修改其指向的元素。
迭代器都可以进行++
操作。反向迭代器和正向迭代器的区别在于:
- 对正向迭代器进行
++
操作时,迭代器会指向容器中的后一个元素; - 而对反向迭代器进行
++
操作时,迭代器会指向容器中的前一个元素。
以下是不同容器对应的迭代器功能。
容器 | 迭代器功能 |
---|---|
vector | 随机访问 |
deque | 随机访问 |
list | 双向 |
set / multiset | 双向 |
map / multimap | 双向 |
stack | 不支持迭代器 |
queue | 不支持迭代器 |
priority_queue | 不支持迭代器 |
值得注意的有如下几点:
- 双向迭代器不支持用“<”进行比较
- 不支持随机访问的迭代器不能使用下标访问元素
.end()
得到的迭代器指向最后一个元素的下一个元素- 判断一个容器是不是为空,若想用迭代器的用法,建议使用
vec.begin() == vec.end()
,不要使用*vec.begin() == NULL
,会报错
例如,vector 的迭代器是随机迭代器,因此遍历 vector 容器有以下几种做法。下面的程序中,每个循环演示了一种做法。
【实例】遍历 vector 容器。
1 |
|
list 容器的迭代器是双向迭代器。假设 v 和 i 的定义如下:
1 | list<int> v; |
则以下代码是合法的:
1 | for(i=v.begin(); i!=v.end(); ++i) |
以下代码则不合法:
1 | for(i=v.begin(); i<v.end(); ++i) |
因为双向迭代器不支持用“<”进行比较。以下代码也不合法:
1 | for(int i=0; i<v.size(); ++i) |
因为 list 不支持随机访问迭代器的容器,也不支持用下标随机访问其元素。
在 C++中,数组也是容器。数组的迭代器就是指针,而且是随机访问迭代器。例如,对于数组 int a[10],int * 类型的指针就是其迭代器。则 a、a+1、a+2 都是 a 的迭代器。
string
string定义在头文件string
中。
定义
string可以采用如下方式定义:
1 | string s1(); // si = "" |
以下将从字符串下标 n 开始、长度为 m 的字符串称为子串(n, m)
。
赋值
对 string 对象赋值:
可以用
char*
类型的变量、常量,以及 char 类型的变量、常量对 string 对象进行赋值。例如:1
2
3string s1;
s1 = "Hello"; // s1 = "Hello"
s2 = 'K'; // s2 = "K”string 类还有 assign 成员函数,可以用来对 string 对象赋值。assign 成员函数返回对象自身的引用。例如:
1
2
3
4
5string s1("12345"), s2;
s3.assign(s1); // s3 = s1
s2.assign(s1, 1, 2); // s2 = "23",即 s1 的子串(1, 2)
s2.assign(4, 'K'); // s2 = "KKKK"
s2.assign("abcde", 2, 3); // s2 = "cde",即 "abcde" 的子串(2, 3)
访问
1 | string s = "hello"; |
长度
求字符串的长度:length 成员函数返回字符串的长度。size 成员函数可以实现同样的功能。
拼接
string对象中字符串的连接:除了可以使用+
和+=
运算符对 string 对象执行字符串的连接操作外,string 类还有 append 成员函数,可以用来向字符串后面添加内容。append 成员函数返回对象自身的引用。如:
1 | string s1("123"), s2("abc"); |
比较
除了可以用 <、<=、==、!=、>=、> 运算符比较 string 对象外,string 类还有 compare 成员函数,可用于比较字符串。compare 成员函数有以下返回值:
- 小于 0 表示当前的字符串小;
- 等于 0 表示两个字符串相等;
- 大于 0 表示另一个字符串小。
如:
1 | string s1("hello"), s2("hello, world"); |
交换
swap 成员函数可以交换两个 string 对象的内容。例如:
1 | string s1("West”), s2("East"); |
求子串
substr 成员函数可以用于求子串 (n, m),原型如下:
1 | string substr(int n = 0, int m = string::npos) const; |
调用时,如果省略 m 或 m 超过了字符串的长度,则求出来的子串就是从下标 n 开始一直到字符串结束的部分。例如:
1 | string s1 = "this is ok"; |
插入字符串
insert 成员函数可以在 string 对象中插入另一个字符串,返回值为对象自身的引用。例如:
1 | string s1("Limitless"), s2("00"); |
扩容
1 | string s("hello"); |
格式互转
转int
C语言转换形式:
1 |
|
C++转换形式(C++11):
1 |
|
参考
C++ vector用法(详解!!函数,实现)
C++ 标准模板库STL 队列 queue 使用方法与应用介绍(一)
C++ stack(STL stack)用法详解
C++ map用法
C++中的STL中map用法详解
C++迭代器(STL迭代器)iterator详解
C++ queue(STL queue)用法详解
[C++ STL] deque使用详解
vector删除元素之pop_back(),erase(),remove()
C++ priority_queue(STL priority_queue)用法详解
C++ string的用法和例子
C++ string类(C++字符串)完全攻略
C++ set添加、删除和访问(STL set添加、删除和访问)元素详解
c++优先队列(priority_queue)用法详解
c++中的atoi()和stoi()函数的用法和区别
C++ - string类型转换int类型
c++ map查找key
vector的几种初始化及赋值方式
c++ map删除元素的三种方式