我们上篇文章讲述了C++中的一些基础语法和常用函数(从C语言的使用转换到C++(上篇)——刷题、竞赛篇),我们本篇文章讲述C++STL的使用。
一、C++STL的简介
STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用。例如,由于STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组;
STL另一个重要特性是它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。你在STL中找不到任何明显的类继承关系。这好像是一种倒退,但这正好是使得STL的组件具有广泛通用性的底层特征。另外,由于STL是基于模板,内联函数的使用使得生成的代码短小高效。
二、STL的使用详解
2、1 STL之动态数组vector的使用
在c语言中我们学习了数组的使用,如:int arr[10]。我们在使用的过程中也发现其缺点,我们不能随意的改变数组的长度。在C++中我们可以使用动态数组vector来完全代替c语言中的数组。动态数组vector能够在运行阶段设置数组的长度、在末尾和中间插入数据、长度可以任意改变。相对c语言中的数组来说,动态数组vector很方便、很实用。
动态数组vector在头文件vector中,也在命名空间std里面。所以使用动态数组vector时,我们要引入#include<vector>和using namespace std;
vector、stack、queue、map、set 这些在C++中都叫做容器,这些容器的大小都可以用.size()获取到。我们快来看一下具体的使用方法:
#include<iostream> #include<vector> using namespace std; int main() { vector<int> v1; //定义一个的整形动态数组vector v1,定义的时候并没有分配大小 cout << v1.size() << endl; //输出动态数组vector v1的大小 return 0; }
在上面的代码中,我们简单的定义了动态数组vector,并且计算了其大小。注意:动态数组vector在C++中叫做容器,我们可以用.size()来计算出其大小。
上述我们在定义的时候并没有分配大小,所以用.size()来计算出其大小时,结果为0
我们接着看动态数组vector的其他用法:
#include<iostream> #include<vector> using namespace std; int main() { //vector<int> v1; //定义一个的整形动态数组vector v1,定义的时候并没有分配大小 //cout << v1.size() << endl; //输出动态数组vector v1的大小 vector<int> v(10); //直接定义长度为10的int数组,默认每个元素的值为0 vector<int> v1; v1.resize(8); //先定义了一个vector v1的动态数组,然后再用resize设置长度为8 vector<int> v2(100, 9); //把长度为100的数组的所有值都初始化为9 v[1] = 2; //可以直接用下标来访问,也可用迭代器访问 return 0; }
不管是vector 、 stack 、 queue 、 map还是set 都有很多好用的方法,这些方法都可以在www.cplusplus.com官方网站中直接查询官方文档,上面有方法的讲解和代码示例。比如进入官网搜索 vector ,就会出现 vector拥有的所有方法,点进去一个方法就能看到这个方法的详细解释和代码示例~当然我们平时写算法用不到那么多方法啦,只有几个是常用的。以下是一些常用的 vector方法:
#include<iostream> #include<vector> using namespace std; int main() { vector<int> a; //定义时不指定vector的大小 cout << a.size() << endl; // a的大小为0 for (int i = 0; i < 10; i++) { a.push_back(i); // 向a中末尾插入0到9 } cout << a.size() << endl; // a的大小为10; vector<int> b(15); //定义时指定b的大小为15,各个元素默认值为0 cout << b.size() << endl; //b的大小为15 for (int i = 0; i < b.size(); i++) { b[i] = 15; //给b中的每个元素赋值 } for (int i = 0; i < b.size(); i++) { cout << b[i] << " "; //输出b中的元素 } cout << endl; vector<int> c(20, 2); //定义时指定c的大小为20,各个元素默认值为2 for (int i = 0; i < c.size(); i++) { cout << c[i] << " "; //输出c中的元素 } cout << endl; for (auto it = c.begin(); it != c.end(); it++) //迭代器访问 { cout << *it << " "; } return 0; }
容器vector , set , map这些遍历的时候都是使用迭代器访问的,(c.begin()是一个指针,指向容器的第一个元素,c.end()指向容器的最后一个元素的后一个位置)。
上述代码的运行结果如下图:
2、2 STL之集合set的使用
set是集合,一个 set里面的各元素是各不相同的,而且 set 会按照元素进行从小到大排序。以下是set的常用用法:
#include <iostream> #include <set> using namespace std; int main() { set<int> s; //定义一个集合 s.insert(1); //向集合里面插入一个1 cout << *(s.begin()) << endl; // ᬌ输出集合中的第一个元素 for (int i = 0; i < 10; i++) { s.insert(i); // 向集合中插入十个元素 } for (auto it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl << (s.find(2) != s.end()) << endl; //查找集合s中的值,如果结果等于s.end()表示未找到(因为s.end()表示s的最后一个元素的下一个元素所在的位置) cout << (s.find(10) != s.end()) << endl; // s.find(10) != s.end() s.erase(1); // s.erase( 1);//删除集合s中的1这个元素 cout << (s.find(1) != s.end()) << endl; //这时候元素1就应该找不到了 return 0; }
上述代码的运行结果如下图:
2、3 STL之映射map的使用
map是键值对,比如一个人名对应一个学号,就可以定义一个字符串string类型的人名为“键”,学号int类型为“值”,如map<string, int>m;当然键、值也可以是其它变量类型。map 会自动将所有的键值对按照键从小到大排序,map使用时的头文件 #include <map>以下是 map中常用的方法:
#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, int> m; //定义一个空的map m,键是string类型的,值是int类型的 m["hello"] = 2; //将key为"hello", value为2的键值对(key-value)存入map中 cout << m["hello"] << endl; //访问map中key为"hello"的value,如果key不存在,则返回0 cout << m["world"] << endl; //返回0 m["world"] = 3; //将"world"键对应的值修改为3 m[","] = 1; //设立一组键值对,键为",”值为1 for (auto it = m.begin(); it != m.end(); it++) { //用迭代器遍历,输出map中所有的元素,键用it->first获取,值用it->second获取 cout << it->first << " " << it->second << endl; } //访问map的第一个元素,输出它的键和值 cout << m.begin()->first << " " << m.begin()->second << endl; //访问map的最后一个元素,输出它的键和值 cout << m.rbegin()->first << " " << m.rbegin()->second << endl; //输出map的元素个数 cout << m.size() << endl; return 0; }
上述代码的运行结果如下图:
2、4 STL之栈stack的使用
栈stack在头文件 #include <stack>中,是数据结构里面的栈。我们知道栈是先进后出的一个原则。以下是常用用法:
#include <iostream> #include <stack> using namespace std; int main() { stack<int> s; //定义一个空栈s for (int i = 0; i < 6; i++) { s.push(i); //将元素i压入栈s中 } cout << s.top() << endl; //访问s的栈顶元素 cout << s.size() << endl; //输出s的元素个数 s.pop(); //移除栈顶元素 cout << s.size() << endl; //输出s的元素个数 cout << s.top() << endl; //访问s的栈顶元素 return 0; }
上面代码的运行结果如下图:
2、5 STL之队列queue的使用
队列queue 在头文件 #include<queue>中,是数据结构里面的队列。队列遵循先进先出的原则。以下是常用用法:
#include <iostream> #include <queue> using namespace std; int main() { queue<int> q; //定义一个空队列q for (int i = 0; i < 10; i++) { q.push(i); //将i的值依次压入队列q中 } cout << q.front() << " " << q.back() << endl; //访问队列的队首元素和队尾元素 cout << q.size() << endl; //输出队列的元素个数 q.pop(); //移除队列的队首元素 cout << q.front() << endl; cout << q.size() << endl; //输出队列的元素个数 return 0; }
上述代码的运行结果如下图:
2、6 STL之unordered_map和unordered_set的使用
unordered_map在头文件#include<unordered_map>中,unordered_set 在头文件#include<unordered_set>中。unordered_map和 map(或者unordered_set和 set )的区别是,map 会按照键值对的键 key进行排序(set里面会按照集合中的元素大小进行排序,从小到大顺序),而unordered_map(或者unordered_set)省去了这个排序的过程,如果偶尔刷题时候用map或者set 超时了,可以考虑用unordered_map(或者_unordered_set)缩短代码运行时间、提高代码效率。至于用法和map .set是一样的。
三、总结
学到这里我们发现,用C++来刷题确实会方便很多。例如,STL中已有栈、队列等容器。而c语言却没有,有些题目做起来就麻烦了很多。
STL的使用给我们带来了很大的便利,也是哦我们重点掌握的内容。学到这里基本上用C++写算法题没有问题。我们需要做的就是通过刷题,进而更加熟练的掌握。
希望以上内容对你有所帮助,感谢阅读ovo~