C++核心编程之STL
STL初识:从零开始的奇幻冒险
1 STL的诞生:一场代码复用的革命
很久很久以前,在编程的世界里,开发者们每天都在重复造轮子。无论是数据结构还是算法,每个人都得从头开始写,仿佛在无尽的沙漠中寻找绿洲。直到有一天,C++的面向对象和泛型编程思想横空出世,带来了复用性的曙光。于是,STL(Standard Template Library,标准模板库)应运而生,成为了拯救开发者于水深火热中的英雄。
2 STL基本概念:容器、算法与迭代器的三角恋
STL,全称标准模板库,是C++中的一把瑞士军刀。它主要由三大核心组成:
-
容器(Container):用来存放数据的各种数据结构,比如数组、链表、栈、队列等。
-
算法(Algorithm):用来处理数据的各种操作,比如排序、查找、遍历等。
-
迭代器(Iterator):容器和算法之间的桥梁,让它们能够无缝连接。
STL的代码几乎都是模板类或模板函数,这意味着你可以用一套代码处理各种数据类型,真正做到“一次编写,到处运行”。
3 STL六大组件:容器、算法、迭代器、仿函数、适配器、空间配置器
STL不仅仅是一个库,它更像是一个精密的机器,由六大组件构成:
-
容器:各种数据结构,如
vector
、list
、map
等,用来存放数据。 -
算法:各种常用的操作,如
sort
、find
、copy
等,用来处理数据。 -
迭代器:容器和算法之间的胶水,让它们能够协同工作。
-
仿函数:行为像函数的对象,可以作为算法的策略。
-
适配器:用来修饰容器、仿函数或迭代器的接口,让它们更灵活。
-
空间配置器:负责内存的分配与管理,确保资源的高效利用。
这六大组件共同构成了STL的强大功能,让开发者能够轻松应对各种复杂的编程任务。
4 容器、算法、迭代器:STL的三剑客
容器:你可以把它想象成一个魔法背包,里面可以装各种类型的数据。STL提供了多种容器,比如vector
(动态数组)、list
(链表)、map
(映射表)等。这些容器分为两类:
-
序列式容器:元素按顺序排列,比如
vector
和list
。 -
关联式容器:元素之间没有严格的物理顺序,通常基于二叉树结构,比如
map
和set
。
算法:算法就像是解决问题的魔法咒语。STL提供了大量的算法,比如sort
(排序)、find
(查找)、for_each
(遍历)等。算法分为两类:
-
质变算法:会改变容器中的元素,比如
copy
和replace
。 -
非质变算法:不会改变容器中的元素,比如
find
和count
。
迭代器:迭代器就像是魔法棒,让你能够遍历容器中的元素,而不需要知道容器的内部结构。每个容器都有自己的迭代器,迭代器的种类也很多,从简单的输入迭代器到功能强大的随机访问迭代器,应有尽有。
每个容器都有自己专属的迭代器。迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针。
种类 | 功能 | 支持运算 |
---|---|---|
输入迭代器 | 对数据的只读访问 | 只读,支持++、==、!= |
输出迭代器 | 对数据的只写访问 | 只写,支持++ |
前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持++、-- |
随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 | 读写,支持++、--、[n]、-n、<、<=、>、>= |
常用的容器中迭代器种类为双向迭代器和随机访问迭代器
5 容器算法迭代器初识:从代码中感受STL的魅力
5.1 vector存放内置数据类型
vector
是STL中最常用的容器之一,你可以把它看作是一个动态数组。下面是一个简单的例子,展示了如何向vector
中插入数据并遍历它:
- 容器: vector
- 算法: for_each
- 迭代器: vector<int>::iterator
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm> // 标准算法头文件
// vector存放内置数据类型
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);
// 通过迭代器访问容器中的数据
// vector<int>::iterator itBegin = v.begin(); //起始迭代器,指向容器中第一个元素
// vector<int>::iterator itEnd = v.end(); // 结束迭代器,指向容器中最后一个元素的下一个位置
// // 第一种遍历方式
// while (itBegin != itEnd)
// {
// cout<<*itBegin<<endl;
// itBegin++;
// }
// // 第二种遍历方式 就是将上面的进行改进优化
// for(vector<int>::iterator it=v.begin();it != v.end(); it++)
// {
// cout<<*it<<endl;
// }
// 第三种遍历方式 利用STL提供遍历算法
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
system("pause");
return 0;
}
5.2 Vector存放自定义数据类型
vector
不仅可以存放内置数据类型,还可以存放自定义的数据类型。比如,我们可以创建一个Person
类,并将其对象存入vector
中:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm> // 标准算法头文件
#include<string>
// vector存放自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void test01()
{
vector<Person>v;
Person p1("孙悟空", 25);
Person p2("猪八戒", 15);
Person p3("钟无艳", 36);
Person p4("兰陵王", 50);
Person p5("安琪拉", 18);
// 向容器中添加数据
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<<"姓名:"<< (*it).m_Name<<" 年龄:"<<(*it).m_Age<<endl;
cout<<"姓名:"<< it->m_Name <<" 年龄:"<< it->m_Age <<endl;
}
}
// 存放自定义数据类型 指针
void test02()
{
vector<Person*>v;
Person p1("孙悟空", 25);
Person p2("猪八戒", 15);
Person p3("钟无艳", 36);
Person p4("兰陵王", 50);
Person p5("安琪拉", 18);
// 向容器中添加数据
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<<"姓名:"<< (*it)->m_Name<<" 年龄:"<<(*it)->m_Age<<endl;
// cout<<"姓名:"<< it->m_Name <<" 年龄:"<< it->m_Age <<endl;
}
}
int main()
{
// test01();
test02();
system("pause");
return 0;
}
5.3 Vector容器嵌套容器
STL的容器还可以嵌套使用,比如vector
中可以存放另一个vector
。下面是一个嵌套容器的例子:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm> // 标准算法头文件
#include<string>
// vector容器嵌套容器
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);
}
// 将小容器插入大容器中
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++)
{
// (*it) ---- 容器 vector<int>
for(vector<int>::iterator vit=(*it).begin(); vit!=(*it).end();vit++)
{
cout<<*vit<<" ";
}
cout<<endl;
}
}
int main()
{
test01();
system("pause");
return 0;
}
结语:STL的奇幻之旅才刚刚开始
STL就像是一个充满魔法的工具箱,里面装满了各种强大的工具。通过容器、算法和迭代器的组合,你可以轻松解决各种复杂的编程问题。这只是STL的入门,随着你深入学习,你会发现它的更多神奇之处。准备好踏上这段奇幻的编程之旅了吗?STL的世界正等着你去探索!