C++最大的特点之一就在于其语法的灵活性和强大的库,STL(Standard Template Library 标准模板库)是C++自带的数据结构的库,在使用的时候只需要加上对应的头文件,这极大的方便了开发者,因为这样就不用做大量的重复性的工作,也就是不会重复造轮子,但是,由于STL的内容比较抽象,并且其语法难度又较高,所以会让刚入门的同学望而却步,今天这篇文章主要是针对常用的几个数据结构进行一个入门的教学,并且展示一些常见的应用。
首先我们先了解一下一些概念:
1.泛型编程:
泛型编程的概念其实很好理解,例如我有一个函数进行加法计算,那么我需要确定函数的返回值类型和参数类型,但是C++中基本数据类型有很多,所以如果我们利用重载的方式去写代码就会写很多重复性的东西,这样会加大程序员的工作量,所以泛型编程的概念由此而生,我们利用一种抽象的类型代表所有的类型,这样的话我们只要在使用的时候传入我们需要的数据类型即可,这样可以大大降低工作量。
2.容器
我们知道数据结构其实就是数据的组织形式,那么容器其实就是根据不同的数据结构用于存放数据用的,有些容器的底层实现十分复杂,所以不在这篇文章的讨论范围内,初学者只要关心如何使用即可,同时在C++中,所有容器的本质都是类模板,所以使用时都要按照类模板的语法规则使用。
3.迭代器
首先了解迭代器的概念,我们既然有了容器,那么我们要对容器中的数据进行访问,这个时候我们就要用到迭代器,迭代器是一种泛化的指针,我们在使用迭代器的时候基本可以类比成指针的操作来理解。
以上三个概念就是STL入门所需要知道的基本概念,有了这三个概念的,我们接下来可以正式开始入门STL了。
先来介绍几个常用的容器:
1.vector容器,vector本意向量,不过这个容器和向量一点关系都没有,vector本质上是一个动态数组,就是大小可以改变的数组,具有很强的灵活性。
2.queue容器,queue本意队列,在STL中就是队列的数据结构,其数据的规律是后进先出 (LIFO),我们对其进行操作时只能在尾端插入数据或者在头端移除数据。
3.deque容器,deque是双端队列,支持两端数据的插入和移除。
4.stack容器,stack就是栈容器,其数据存储符合先进后出(FILO)的形式,我们只能在栈顶的地方对数据进行添加或移除。
5.list容器,list容器叫做链表,对元素的插入和删除具有很高的效率,但是对于查找元素的效率不高。
6.set容器,set就是集合,普通的set容器不允许重复元素出现,并且对于基本数据类型在插入数据时会自动将数据进行排序,如果想插入重复数据就应该使用mutilset,如果不想对数据进行排序就应该使用unordered_set(哈希表).
7.map容器,map就是图,这个需要可能需要一点离散数学的概念才知道图是什么,这个容器的特点就是每个元素都由键值对组成,每一个数据对应一个键,在查找数据时根据键值进行查找,具有极高的查找效率,和set容器一样,对于基本数据类型,在插入数据时map容器会自动拍好序,并且不能出现键值相同的元素,如果想出现相同元素需要使用mutilmap,如果不需要对元素进行排序可以使用unordered_map。
以上六个容器就是STL中常用容器,接下来介绍这几个容器相应的成员函数。
begin, end, rbegin, rend, size, erase, clear, insert, push_back, pop_back, pop_front, top, pop, push, empty
成员函数 | 函数作用 | 适用容器 |
---|---|---|
begin() | 返回第一个元素的正向迭代器 | 除了stack和queue外 |
end() | 返回最后一个元素的下一个位置的迭代器 | 同上 |
rbegin() | 返回最后一个元素的反向迭代器 | 同上 |
rend() | 返回第一个元素前一个位置的迭代器 | 同上 |
push_back() | 在尾端插入数据 | vector和deque,list |
push_front() | 在头端插入数据 | deque,list |
pop_back() | 删除尾端数据 | vector和deque,list |
pop_front() | 删除头端数据 | deque.list |
push() | 插入数据 | stack和queue |
pop() | 删除数据(对于queue是删除头端数据,stack是删除栈顶元素) | stack和queue |
insert() | 在指定位置插入数据(对于set和map是直接插入) | 除了stack和queue外 |
top() | 返回栈顶元素 | stack |
clear() | 清空容器 | 所有容器 |
empty() | 判断容器是否为空,为空返回true,不为空返回false | 所有容器 |
erase() | 清除区间内的数据 | 所有容器 |
以上所举出的例子只不过是STL中最为常用的函数,其作用和语法基本一致,读者如果想了解更多,作者这边推荐一个C++的官方网站Containers - C++ Reference这个网站上涵盖了STL所有容器的用法,还有一些C++11新容器,这里没有展示,只不过网站是英文的所以需要有点英语基础看起来不会太吃力。
接下来演示部分容器的使用方法:
#include <vector>//使用容器需要包含对应的头文件
#include <deque>
#include <set>
#include <map>
using namespace std;
int main()
{
vector<int>v;
deque<int>d;
set<int>s;
map<int, int>m;//map容器存放的都是pair对组,关于对组的使用不会的自行百度
//插入基本数据以用于演示
for (int i = 0; i < 10; i++)
{
v.push_back(i);
d.push_back(i);
s.insert(i);//对于set和map只能用insert插入数据
m.insert(make_pair(i, i));
}
//遍历输出
//对于四种容器一下使用不同的方法进行遍历
//vector
//方法1
for (int i = 0; i < 10; i++)
{
cout << v[i] << " "; // vector可以利用下标进行访问元素
}
cout << endl;
//方法二利用迭代器进行容器遍历
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
cout << "----------------------------" << endl;//分割线
//deque
//方法一
for (int i = 0; i < 10; i++)
{
cout << d[i] << " ";
}
cout << endl;
//方法二
for (deque<int>::iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//方法三
while(!d.empty())
{
cout << *(d.begin()) << " ";
d.pop_front();
}
//set容器
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//map容器
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
//这里我们可以通过迭代器来访问m中的键和值
cout << "key:" << it->first << " " << "value:" << it->second << " ";
}
cout << endl;
}