【C++】STLday1

STL

  • STL:Standard Template Library,标准模板库,C++ 标准库一部分,基于模板实现,复用数据结构与算法代码

STL 六大组件

  • 容器 container:各类数据结构,存放数据(vector、list、map...)
  • 算法 algorithm:通用算法,排序、查找、拷贝等
  • 迭代器 iterator :容器和算法之间的桥梁,类似指针,用来遍历容器元素
  • 仿函数 functor :重载()的类,行为像函数,给算法提供自定义策略
  • 适配器 adapter:包装其他组件,修改接口(stack、queue 就是容器适配器)
  • 空间配置器 allocator:负责内存空间分配、释放、管理

组件交互关系

  • 容器依靠空间配置器申请内存

  • 算法通过迭代器访问容器里的数据

  • 仿函数给算法提供自定义策略

  • 适配器用来修饰容器 / 仿函数 / 迭代器接口

三大核心组件

  • 三大核心:容器、算法、迭代器

容器

  • 分为 序列式容器 和 关联式容器

  • 序列式容器 :元素位置由插入顺序 决定,元素是有序排列,但值不一定有序
    1)vector、deque、list、forward_list

  • 关联式容器 :容器内部自带排序规则,元素位置由元素值 / 键值 决定,自动有序
    1)map、set、multimap、multiset

算法

  • 分为 质变算法 、非质变算法

  • 质变算法 :运算过程修改容器区间内元素内容
    1)例:copy、replace、sort

  • 非质变算法 :运算不会修改元素 ,只做查找、统计、遍历
    1)例:find、count、for_each(只读版本)

迭代器

  • 迭代器是算法访问容器的统一接口,不同容器迭代器能力不同

  • 双向迭代器 :支持 ++、--,可以向前、向后遍历;不支持随机跳跃
    1)list、map、set 的迭代器

  • 随机访问迭代器 :继承双向迭代器能力,额外支持 +n、-n、[],可以直接跳跃访问元素
    1)vector、deque 的迭代器

三大组件关系总结

  • 容器负责存储数据,并对外提供迭代器;
    算法通过迭代器,间接操作容器里面的元素,算法本身不依赖具体容器

STL 工作机制

  • 核心原理
    1)STL 的核心思想:
    容器负责存数据,并且对外提供迭代器(begin ()、end ())
    算法不直接访问容器,只通过迭代器区间 [begin, end) 来遍历、操作元素
    2)[begin, end) 左闭右开区间:
    begin 指向第一个元素,end 指向最后一个元素的下一个位置,
    end 位置不存储有效数据

复制代码
  //模拟数组容器
  template <class T>
  class MyArray
  {
  public:
  	//迭代器:把原生指针T* 别名叫做iterator
  	typedef T* iterator;

  	MyArray()
  	{
  		mCapacity = 10; //容量 :总空间大小
  		mSize = 10; // 有效元素个数
  		p = new T[mCapacity]; //开辟堆内存

  		for (int i = 0; i < mCapacity; i++)
  		{
  			p[i] = i + 1; //初始化:1,2,3,4....10
  		}
  	}

  	//begin:返回起始迭代器,指向第一个元素
  	T* begin()
  	{
  		return p;
  	}

  	//end,返回结束迭代器,指向末尾下一个位置(无有效数据)
  	T* end()
  	{
  		return p + mSize;
  	}

  public:
  	T* p;// 堆数组首地址
  	int mCapacity; //容量
  	int mSize; //有效数据数量
  };


  //算法:打印区间元素,不依赖MyArray这个容器
  //只要求传入一对迭代器 [begin,end]

  template <class T>
  void printArray(T begin, T end)
  {
  	for (; begin != end; begin++)
  	{
  		cout << *begin << " "; //解引用迭代器,拿到元素
  	}
  	cout << endl;
  }

  void test1()
  {
  	MyArray<int> arr;
  	//获取迭代器
  	MyArray<int>::iterator begin = arr.begin();
  	MyArray<int>::iterator end = arr.end();
  	printArray(begin, end);
  }
重点
  • 迭代器本质
    1)迭代器是容器对外暴露的访问接口
    2)对于 list、map,迭代器不是原生指针,但是用法和指针一样(支持*解引用、++)

  • 容器和算法解耦(STL 最核心的设计)

    1)容器只负责管理内存、存放数据,提供begin()和end()拿到迭代器
    2)算法不关心底层是什么容器,只接收一对迭代器区间[begin,end)
    3)算法和容器完全分离,这就是 STL 的精髓

  • 左闭右开区间 [begin, end)
    1)begin:有效第一个元素
    2)end:尾后迭代器,不是有效元素,是判断循环终止条件
    3)循环条件:begin != end

  • typedef T* iterator;作用
    1)给指针起别名iterator,模仿 STL 标准写法
    2)使用时MyArray<int>::iterator,和vector<int>::iterator写法一模一样

STL中的hello world


核心:vector 容器四种用法

  • 存放基础数据类型 int
  • 存放自定义类对象
  • 存放自定义类指针
  • 容器嵌套容器 vector<vector<int>>

vector 存放内置数据类型

复制代码
  void MyPrint(int val)
  {
  	cout << val << " ";
  }

  void test1()
  {
  	vector<int>v;
  	v.push_back(10);
  	v.push_back(20);
  	v.push_back(30);
  	v.push_back(40);
  	v.push_back(50);
  	vector<int>::iterator begin = v.begin();
  	vector<int>::iterator end = v.end();

  	//for_each : 遍历算法,接收迭代区间+回调函数
  	for_each(begin, end, MyPrint);
  	cout << endl;
  }
  • for_each 底层伪代码

    复制代码
    void _For_each(_InIt _First, _InIt _Last, _Fn1& _Func)
    {	
    	for (; _First != _Last; ++_First)
    		_Func(*_First);
    }

    1)for_each 会不断移动迭代器,取出元素,传给回调函数


vector 存放自定义对象

  • 重点:vector<Maker>存放的是对象副本,push_back 的时候会拷贝临时对象存入容器

复制代码
  class Maker
  {
  public :
  	string name;
  	int age;

  	Maker(string name, int age)
  	{
  		this->name = name;
  		this->age = age;
  	}
  };

  //重载 << 运算符 ,支持cout 打印Maker对象
  ostream& operator<<(ostream& out, Maker& m)
  {
  	out << "Name: " << m.name << " Age: " << m.age << endl;
  	return out;
  }

  void test2()
  {
  	vector<Maker>v;
  	//会调用Maker构造函数,创建临时对象,存入容器(拷贝)
  	v.push_back(Maker("悟空", 18));
  	v.push_back(Maker("小林", 19));
  	v.push_back(Maker("贝吉塔", 25));
  	v.push_back(Maker("龟仙人", 21));
  	v.push_back(Maker("短笛", 29));

  	vector<Maker>::iterator begin = v.begin();
  	vector<Maker>::iterator end = v.end();

  	while (begin != end)
  	{
  		cout << (*begin);  //*begin 取出Maker对象
  		begin++;
  	}
  }

vector 存放对象指针

  • vector<Maker*>
复制代码
  class Maker
  {
  public :
  	string name;
  	int age;

  	Maker(string name, int age)
  	{
  		this->name = name;
  		this->age = age;
  	}
  };

  //重载 << 运算符 ,支持cout 打印Maker对象
  ostream& operator<<(ostream& out, Maker& m)
  {
  	out << "Name: " << m.name << " Age: " << m.age << endl;
  	return out;
  }

  void test3()
  {
  	vector<Maker*>v;
  	//在堆区创建对象
  	Maker* m1 = new Maker("悟空", 18);
  	Maker* m2 = new Maker("小林", 19);
  	Maker* m3 = new Maker("贝吉塔", 25);
  	Maker* m4 = new Maker("龟仙人", 21);
  	Maker* m5 = new Maker("短笛", 29);
  	v.push_back(m1);
  	v.push_back(m2);
  	v.push_back(m3);
  	v.push_back(m4);
  	v.push_back(m5);

  	vector<Maker*>::iterator begin = v.begin();
  	vector<Maker*>::iterator end = v.end();
  	while (begin != end)
  	{
  		//*begin 得到的的是Maker*指针 用->访问
  		cout << (*begin)->name << " " << (*begin)->age << endl;
  		begin++;
  	}

  	//堆内存必须手动释放
  	delete m1;
  	delete m2;
  	delete m3;
  	delete m4;
  	delete m5;
  }
  • 区分
    1)vector<Maker>:存对象,容器销毁自动销毁对象,不需要手动 delete
    2)vector<Maker*>:存指针,容器只保存地址,不会释放堆上的对象,
    必须手动 delete,否则内存泄漏

容器嵌套容器

  • vector<vector<int>>(二维数组效果)

复制代码
  //容器嵌套相当于二维数组
  void test4()
  {
  	vector < vector<int>>vs;

  	vector<int>v1;
  	vector<int>v2;
  	vector<int>v3;
  	vector<int>v4;
  	vector<int>v5;
  	for (int i = 0; i < 5; i++)
  	{
  		v1.push_back(i + 10);
  		v2.push_back(i + 10);
  		v3.push_back(i + 10);
  		v4.push_back(i + 10);
  		v5.push_back(i + 10);
  	}

  	vs.push_back(v1);
  	vs.push_back(v2);
  	vs.push_back(v3);
  	vs.push_back(v4);
  	vs.push_back(v5);

  	vector<vector<int>>::iterator begin=vs.begin();
  	vector<vector<int>>::iterator end = vs.end();

  	while (begin != end)
  	{
  		// *begin 得到内层 vector<int>
  		vector<int>::iterator sbegin = (*begin).begin();
  		vector<int>::iterator send = (*begin).end();
  		while (sbegin != send)
  		{
  			cout << *sbegin << " ";
  			sbegin++;
  		}

  		cout << endl;
  		++begin;

  	}
  }
  • 外层迭代器遍历外层容器,解引用*begin拿到内层容器,再取内层迭代器遍历
相关推荐
无名猿1 小时前
左值、右值、纯右值、将亡值:值类别入门
c++·内存管理·现代c++·语法基础
程序员老陆1 小时前
C++ 将亡值(xvalue)深度解析:从表达式分类到参数传递陷阱
c++·程序设计
沫璃染墨2 小时前
《Qt从零入门系列(十二):Qt文件操作详解——从QFile读写到QFileInfo与记事本实战》
开发语言·网络·c++·qt·交互·信号处理·文件
青少儿编程课堂2 小时前
树上启发式合并详解:子树颜色众数统计与复杂度拆解
c++·python·算法·bfs·信息学竞赛
路弥行至2 小时前
【Head First 设计模式】第 2 章:观察者模式 —— 用现代 C++ 重新解读“交互对象的松耦合
c++·经验分享·笔记·观察者模式·设计模式·入门教程·headfirst
YYYing.2 小时前
【设计模式系列 (九) 】装饰器模式
c++·后端·设计模式·装饰器模式·c/c++
elseif1233 小时前
【2026 CSP-J】【逐题精讲】超详细(15道选择,3道阅读,2道完善)
java·开发语言·c++·算法·csp
殷色玫瑰3 小时前
C语言编译和链接:从 .c到 .exe,程序到底经历了什么?
linux·c语言·c++·算法
keep intensify3 小时前
C++20线程池
c++·算法·c++20