【STL】概述及总结(很全!!!)

STL: (Standard Template Library) 标准模板库

STL广义上讲分为三类,algorithm算法container容器iterator迭代器,容器和算法通过迭代器可以进行无缝地连接,容器里面存数据,算法进行排序或查找,迭代器是用来访问容器里的数据的。

STL的一个重要特点就是数据结构和算法的分离,即数据的存储和数据的访问进行了分离,如栈的栈顶指针为栈数据的常用访问,而栈的数据存储是通过栈的数据结构。

STL发展

长久以来,软件界一直希望建立一种可重复利用的东西,以及一种得以制造出”可重复运用的东西”的方法,从函数(functions),类别(classes),函数库(function libraries),类别库(class libraries)、各种组件,从模块化设计,到面向对象(object oriented ),为的就是复用性的提升。

复用性必须建立在某种标准之上。但是在许多环境下,就连软件开发最基本的数据结构(data structures) 和算法(algorithm)都未能有一套标准。大量程序员被迫从事大量重复的工作,竟然是为了完成前人已经完成而自己手上并未拥有的程序代码,这不仅是人力资源的浪费,也是挫折与痛苦的来源。

为了建立数据结构和算法的一套标准,并且降低他们之间的耦合关系,以提升各自的独立性、弹性、交互操作性(相互合作性,interoperability),诞生了STL。

STL(Standard Template Library,标准模板库),是惠普实验室开发的一系列软件的统称。现在主要出现在 c++中,但是在引入 c++之前该技术已经存在很长时间了。

容器和算法之间通过迭代器进行无缝连接。STL 几乎所有的代码都采用了模板类或者模板函数,这相比传统的由函数和类组成的库来说提供了更好的代码重用机会。

它的发展历程可以从以下几个方面来讨论:

  • 早期版本:STL最初由Alexander Stepanov和Meng Lee于1994年开发,最初被称为SGI STL(Silicon Graphics Inc. STL)。它的目的是为了在C++中提供高效的数据结构和算法的实现,大大简化了C++程序的开发。早期版本的STL包含容器、迭代器、算法、函数对象等组件。
  • 标准化:由于STL在C++社区中的广泛应用,它于1998年正式被纳入C++标准库中。这一标准化使得STL更加稳定和可靠,成为C++程序员必备的工具之一。
  • 扩展和优化:随着C++标准的不断更新,STL也不断得到扩展和优化。例如,C++11标准中新增了多线程支持,同时STL也在容器、迭代器、算法等方面得到了进一步扩展和优化。此外,一些开源社区也提供了STL的优化版本,如boost库、Eastl等。
  • 应用领域:STL在软件开发中有广泛的应用,包括游戏开发、图形处理、科学计算、数据挖掘等领域。尤其在高性能和高并发的系统开发中,STL的应用更加广泛。

总的来说,STL的发展历程是一个不断完善和拓展的过程,它为C++程序员提供了强大的工具,极大地提高了程序开发效率和性能。

STL的特点

  • 可重用性(stl中几乎所有代码都是通过模板类,模板函数的方式实现)
  • 高性能(map的键值,map采用红黑树的变体来实现,查找某个元素只需log2^n的时间复杂度,即十万条数据差不多只用比较十四次)
  • 高移植性(项目A用STL写的模块可以直接移植到项目B)
  • 跨平台(VS可以在XCode上直接编译)

STL六大组件

STL提供了六大组件,彼此之间可以组合套用,这六大组件分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器。

  • 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据,从实现角度来看,STL容器是一种class template。
  • 算法:各种常用的算法,如sort、find、copy、for_each。从实现的角度来看,STL算法是一种function tempalte.
  • 迭代器:扮演了容器与算法之间的胶合剂,共有五种类型,从实现角度来看,迭代器是一种将operator* , operator-> , operator++,operator–等指针相关操作予以重载的class template. 所有STL容器都附带有自己专属的迭代器,只有容器的设计者才知道如何遍历自己的元素。原生指针(native pointer)也是一种迭代器。
  • 仿函数:行为类似函数,可作为算法的某种策略。从实现角度来看,仿函数是一种重载了operator()的class 或者class template
  • 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
  • 空间配置器:负责空间的配置与管理。从实现角度看,配置器是一个实现了动态空间配置、空间管理、空间释放的class tempalte.

STL六大组件的交互关系,容器通过空间配置器取得数据存储空间,算法通过迭代器存储容器中的内容,仿函数可以协助算法完成不同的策略的变化,适配器可以修饰仿函数。

迭代器

迭代器(Iterator)是一种设计模式,在遍历一个集合(如数组、链表、集合等)时,提供一种遍历方式,而不需要暴露内部实现。通过迭代器,我们可以逐个访问集合中的元素,而不需要知道实际存储结构或者底层数据类型。

迭代器模式的核心是将集合对象和遍历算法分离,使得集合对象和遍历算法能够独立地变化。迭代器模式定义了一个迭代器接口,包含了遍历集合所需要的方法,如获取下一个元素、判断是否还有下一个元素等。各个集合类实现此接口,提供自己的迭代器实现。

迭代器的种类:

迭代器功能描述
输入迭代器提供对数据的只读访问只读,支持++、==、!=
输出迭代器提供对数据的只写访问只写,支持++
前向迭代器提供读写操作,并能向前推进迭代器读写,支持++、==、!=
双向迭代器提供读写操作,并能向前和向后操作读写,支持++、–
随机访问迭代器提供读写操作,并能以跳跃的方式访问容器的任意数据,是功能最强的迭代器读写,支持++、–、[n]、-n、<、<=、>、>=

实例:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
 
//STL 中的容器 算法 迭代器
void test01(){
	vector<int> v; //STL 中的标准容器之一 :动态数组
	v.push_back(1); //vector 容器提供的插入数据的方法
	v.push_back(5);
	v.push_back(3);
	v.push_back(7);
	//迭代器
	vector<int>::iterator pStart = v.begin(); //vector 容器提供了 begin()方法 返回指向第一个元素的迭代器
	vector<int>::iterator pEnd = v.end(); //vector 容器提供了 end()方法 返回指向最后一个元素下一个位置的迭代器
	//通过迭代器遍历
	while (pStart != pEnd){
		cout << *pStart << " ";
		pStart++;
	}
	cout << endl;
	//算法 count 算法 用于统计元素的个数
	int n = count(pStart, pEnd, 5);
	cout << "n:" << n << endl;
}
//STL 容器不单单可以存储基础数据类型,也可以存储类对象
class Teacher
{
public:
	Teacher(int age) :age(age){};
	~Teacher(){};
public:
	int age;
};
void test02(){
	vector<Teacher> v; //存储 Teacher 类型数据的容器
	Teacher t1(10), t2(20), t3(30);
	v.push_back(t1);
	v.push_back(t2);
	v.push_back(t3);
	vector<Teacher>::iterator pStart = v.begin();
	vector<Teacher>::iterator pEnd = v.end();
	//通过迭代器遍历
	while (pStart != pEnd){
		cout << pStart->age << " ";
		pStart++;
	}
	cout << endl;
}
//存储 Teacher 类型指针
void test03(){
	vector<Teacher*> v; //存储 Teacher 类型指针
	Teacher* t1 = new Teacher(10);
	Teacher* t2 = new Teacher(20);
	Teacher* t3 = new Teacher(30);
	v.push_back(t1);
	v.push_back(t2);
	v.push_back(t3);
	//拿到容器迭代器
	vector<Teacher*>::iterator pStart = v.begin();
	vector<Teacher*>::iterator pEnd = v.end();
	//通过迭代器遍历
	while (pStart != pEnd){
		cout << (*pStart)->age << " ";
		pStart++;
	}
	cout << endl;
}
//容器嵌套容器 难点
void test04()
{
	vector< vector<int> > v;
	vector<int>v1;
	vector<int>v2;
	vector<int>v3;
 
	for (int i = 0; i < 5;i++)
	{
		v1.push_back(i);
		v2.push_back(i * 10);
		v3.push_back(i * 100);
	}
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
 
	for (vector< vector<int> >::iterator it = v.begin(); it != v.end();it++)
	{
		for (vector<int>::iterator subIt = (*it).begin(); subIt != (*it).end(); subIt ++)
		{
			cout << *subIt << " ";
		}
		cout << endl;
	}
} 
int main(){
	//test01();
	//test02();
	//test03();
	test04();
	system("pause");
	return EXIT_SUCCESS;
}

STL容器使用时机

.vectordequelistsetmultisetmapmultimap
典型内存结构单端数组双端数组双向链表二叉树二叉树二叉树二叉树
可随机存取对key而言:不是
元素搜寻速度非常慢对key而言:快对key而言:快
元素安插移除尾端头尾两端任何位置----

**vector的使用场景:**比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。

**deque的使用场景:**比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。

vector与deque的比较:

  1. vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置 却是不固定的。
  2. 如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关。
  3. deque支持头部的快速插入与快速移除,这是deque的优点。

**list的使用场景:**比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。

**set的使用场景:**比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。

**map的使用场景:**比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。

容器:
【STL】string
【STL】vector
【STL】链表(list)
【STL】栈(stack)
【STL】队列(queue)
【STL】set&multiset
【STL】map&multimap

算法:
【STL】排序
【STL】查找

参考博文:

https://blog.csdn.net/soinlove36/article/details/119796794

https://blog.csdn.net/ltzoro/article/details/132102671

https://blog.csdn.net/hoppingg/article/details/130143286

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值