二. STL初识
1. STL的诞生
C++的面向对象和泛型编程思想,目的就是复用性的提升;
大多数情况下,数据结构和算法都未能有一套标准。导致被迫从事大量重复工作
STL的一个重要特性,将数据和和操作分离。数据由容器进行管理,操作则由可定制的算法定义。迭代器在两者之间充当“粘合剂”,以使算法可以和容器交互运作,通过迭代器的协助,我们只需要撰写一次算法,就可以将他应用于任意容器之上,这是因为所有容器的迭代器都是一致的接口。
2. STL基本概念
STL(Standard Template Library , 标准模板库)
STL从广义上分为:容器(container)算法(algorithm)迭代器(iterator)
容器和算法之间通过迭代器进行无缝连接
STL几乎所有的代码都采用了模板类或者模板函数
3. STL六大组件
1) 容器:各种数据结构,如vector , list , deque , set, map等,用来存放数据。(从实现角度看,STL容器是一种类模板)
2)算法:各种常用的算法,如sort , find , copy , for_each等。(从实现角度看,STL算法是一种函数模板)
3)迭代器:扮演了容器与算法之间的胶合剂
4)仿函数:行为类似函数,可作为算法的某种策略
5)适配器(配接器):一种用来修饰容器或者仿函数或者迭代器接口的东西
6)空间配置器:负责空间的配置与管理
4. STL中的容器,算法,迭代器
4.1 容器
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组,链表,树,栈,队列,集合,映射表等
序列式容器:强调值的排序,序列式容器中的每一个元素均有固定的位置。(vector,deque,list,array,string)
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系(set,multiset,map,multimap)
4.2 算法
质变算法:指运算过程中会更改区间内的元素的内容。例如拷贝、替换、删除。
非质变算法:指运算过程中不会更改区间内的元素的内容。例如查找、计数、遍历、寻找极值等。
4.3 迭代器
提供一种方法,使之能够依序访问某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
每个容器都有自己专属的迭代器。
迭代器使用非常类似于指针,初学阶段可以理解迭代器为指针
迭代器种类:
种类 | 功能 | 支持运算 |
---|---|---|
输入迭代器 | 对数据的只读访问 | 只读,支持++,==,!= |
输出迭代器 | 对数据的只写访问 | 只写,支持++ |
前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持++、– |
随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 | <、<=、>、>= |
常用的为双向和随机访问
5. 容器算法迭代初识
STL中最常用的容器为vector,可以理解为数组
5.1 vector存放内置数据类型
容器:vector
算法:for_each
迭代器:vector::iterator
#include <vector>
#include<algorithm>
#include<iostream>
void MyPrint(int val)
{
cout<<val<<endl;
}
void test01()
{
//创建vector容器对象,并且通过模板参数指定容器中存放的数据的类型
vector<int> v;
//向容器中放数据
v.push-back(10);
v.push-back(20);
v.push-back(30);
v.push-back(40);
//每一个容器都有自己的迭代器,迭代器是用来遍历容器中的元素
//v.begin()起始迭代器,这个迭代器指向容器中第一个数据
//v.end()结束迭代器,这个迭代器指向容器元素的最后一个元素的下一个位置
//vector<int>::iterator拿到vector<int>这种容器的迭代器类型
vector<int>::iterator pBegin = v.begin();
vector<int>::iterator pEnd = v.end(); //pBegin,pEnd可以自己定义
//第一种遍历方式
while(pBegin !=pEnd)
{
cout<<*pBegin<<endl;
pBegin ++;
}
//第二种遍历方式
for(vector<int>::iterator it = v.begin(); it!=v.end();it++)
{
cout<<*it<<endl;
}
cout<<endl;
//第三种遍历方式
//使用STL提供标准遍历算法 头文件algorithm
for_each(v.begin(),v.end(),MyPrint);
}
int main()
{
test01();
system("pause");
return 0;
}
5.2 vector存放自定义数据类型
#include<iostream>
#include<vector>
#include<string>
//自定义数据类型
class Person
{
public:
Person(string name,int name)
{
mName=name;
mAge=age;
}
public:
string mName;
int mAge;
};
//存放对象
void test01()
{
vector<Person> v;
//创建数据
Person p1("aaa",10);
Person p2("bbb",20);
Person p3("ccc",30);
Person p4("ddd",40);
Person p5("eee",50);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
for(vector<Person>::iterator it = v.begin(); it!=v.end();it++)
{
cout<<"Name:"<<(*it).mName<<"Age:"<<(*it).mAge<<endl;
}
}
//放对象指针
void test02()
{
vector<Person*> v;
//创建数据
Person p1("aaa",10);
Person p2("bbb",20);
Person p3("ccc",30);
Person p4("ddd",40);
Person p5("eee",50);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
for(vector<Person*>::iterator it = v.begin();it!=v.end(); it++)
{
Person *p=(*it);
cout<<"Name:"<<p->mName<<"Age:"<<(*it)->mAge<<endl;
}
}
5.3 vector容器嵌套容器
#include<vector>
#include<iostream>
//容器嵌套容器
void test01()
{
vector<vector<int>> v;
vector<int> v1; //创建小容器
vector<int> v2;
vector<int> v3;
vector<int> v4;
for(int i=0; i<4; i++) //向小容器中添加数据
{
v1.push_back(i+1);
v2.push_back(i+2);
v3.push_back(i+3);
v4.push_back(i+4);
}
//将容器元素插入到vector v中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
for(vector<vector<int>>::iterator it = v.begin(); it !=v.end(); it++)
{
for(vector<int>::iterator vit =(*it).begin(); vit!=(*it).end();vit++)
//(*it) -> 容器vector<int>
{
cout<<*vit<<" ";
}
cout<<endl;
}
}
int main()
{
... ...
}
补充打印第 i 行第 j 列的代码
void print_arr(int *a, int m ,int n) //m行n列
{
int i, j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
printf("%d",a[i*n+j]); //第i行第j列元素
}
}
}