STL(Standard Template Library)标准模板库简介

STL

  1. 容器(Containers):用来管理某类对象的集合。

  2. 迭代器(Iterators):用来在一个对象集合的元素上进行遍历动作。

  3. 算法(Algorithms):用来处理对象集合中的元素,比如 Sort、Search、Copy、Erase。

容器

为了应付程序中的不同需求,STL 准备了两类共七种基本容器类型:

  • 序列式容器(Sequence containers),此为可序群集,其中每个元素均有固定位置—取决于插入时机和地点,和元素值无关。如果你以追加方式对一个群集插入六个元素,它们的排列次序将和插入次序一致。STL提供了三个序列式容器:向量(vector)、双端队列(deque)、列表(list),此外你也可以把 string 和 array 当做一种序列式容器。

  • 关联式容器(Associative containers),此为已序群集,元素位置取决于特定的排序准则以及元素值,和插入次序无关。如果你将六个元素置入这样的群集中,它们的位置取决于元素值,和插入次序无关。STL提供了四个关联式容器:集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)。

除了以上七个基本容器类别,为满足特殊需求,STL还提供了一些特别的(并且预先定义好的)容器配接器,根据基本容器类别实现而成。包括:

  1. stack
    stack 容器对元素采取 LIFO(后进先出)的管理策略。

  2. queue
    queue 容器对元素采取 FIFO(先进先出)的管理策略。

  3. priority_queue
    优先队列是一种抽象数据类型,行为有些像队列,但先出队列的元素不是先进队列的元素,而是队列中优先级最高的元素,这就类似急诊病人插队的事情发生。优先队列定义在头文件里,用priority_queues声明。

vector

vector(向量): 不定长数组,相比数组更优越。一般来说数组不能动态拓展,因此在程序运行的时候不是浪费内存,就是造成越界。而vector正好弥补了这个缺陷,它的随机访问快,在中间插入和删除慢,但在末端插入和删除快。

特点

  • 拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随机访问,即[]操作符和.at(),但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝,另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了 vector 的效率。

  • 对头部和中间进行插入删除元素操作需要移动内存,如果你的元素是结构或类,那么移动的同时还会进行构造和析构操作,所以性能不高。

  • 对最后元素操作最快(在后面插入删除元素最快),此时一般不需要移动内存,只有保留内存不够时才需要。

例子

定义了一个整形的vector,插入6个元素,然后打印所有元素:

#include <iostream>
#include <vector>
using namespace std;

int main(int argc, char* argv[])
{
	vector<int> vecTemp;

	for (int i = 0; i<6; i++)
		vecTemp.push_back(i);

	for (int i = 0; i<vecTemp.size(); i++)
		cout << vecTemp[i] <<" "; 

	return 0;
}
/*
输出结果:
0 1 2 3 4 5
*/

deque

deque(double-ended-queue)是由一段一段的定量连续空间构成。一旦要在deque的前端和尾端增加新空间,便配置一段定量连续空间,串在整个deque的头端或尾端。因此不论在尾部或头部安插元素都十分迅速。在中间部分安插元素则比较费时,因为必须移动其它元素。deque的最大任务就是在这些分段的连续空间上,维护其整体连续的假象,并提供随机存取的接口。

特点

  • deque 是 list 和 vector 的折中方案。兼有 list 的优点,也有vector 随机线性访问效率高的优点。

  • 支持随机访问,即 [] 操作和 .at(),所以查询效率高;可在双端进行pop、push。

  • 不适合中间插入删除操作;占用内存多。

例子

定义了一个浮点类型的deque,并在容器尾部插入6个元素。

#include<iostream>
#include<deque>
using namespace std;
int main()
{
      deque<float> dequeTemp;
      for (int i=0;i<6;i++)
            dequeTemp.push_back(i);
      for (int i=0;i<n;i++)
            cout<< dequeTemp[i]<<" ";

      return 0;
}
/*
输出结果:
0 1 2 3 4 5
*/

list

list由双向链表(doubly linked list)实现而成,元素也存放在堆中,每个元素都是放在一块内存中,它的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点使得它的随机存取变得非常没有效率,因此它没有提供[]操作符的重载,不支持随机访问。但是由于链表的特点,它可以很有效率的支持任意地方的插入和删除操作。

特点

没有空间预留习惯,所以每分配一个元素都会从内存中分配,每删除一个元素都会释放它占用的内存。
可在任意位置添加删除元素性能都很高,不需要移动内存,当然也不需要对每个元素都进行构造与析构了,所以常用来做随机插入和删除操作容器。
访问开始和最后两个元素最快,其他元素的访问时间一样。

例子

定义了一个空list,准备放置字符,然后将'a'-'z'的所有字符插入其中,利用循环每次打印并移除集合的第一个元素,从而打印出所有元素:

#include<iostream>
#include<list>
using namespace std;

int main()
{
	list<char>listTemp;
	for (char c='a';c <='z';++c)
		listTemp.push_back(c);
	while(!listTemp.empty()) //empty()函数,若变量为空返回true,反之。 
	{
		cout<<listTemp.front()<<" ";
		listTemp.pop_front();
	}
	return 0;
}
/*
输出结果:
a b c d e f g h i j k l m n o p q r s t u v w x y z
*/

set

集合(set)以有序地存储互异元素的容器。其实现是由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种比较元素大小的谓词进行排列。
(谓词(Predicate):谓词就是返回值为真或者假的函数。STL 容器中经常会使用到谓词,用于模板参数。)

特点

  • set 中的元素都是排好序的,集合中没有重复的元素。

  • map 和 set 的插入删除效率比用其他序列容器高,因为对于关联容器来说,不需要做内存拷贝和内存移动。

  • 使用平衡二叉树实现,便于元素查找,且保持了元素的唯一性,以及能自动排序。

  • 每次插入值的时候,都需要调整红黑树,效率有一定影响。

例子

下面这个例子演示的两个特点:有序和不重复。

#include<iostream>
#include<set>

using namespace std;
int main()
{
	set<int> setTemp;
	setTemp.insert(3);
	setTemp.insert(1);
	setTemp.insert(2);
	setTemp.insert(1);
	
	set<int>::iterator it; //迭代器
	for (it = setTemp.begin();it != setTemp.end();it++)
	{
	 	cout << *it  << " ";	
	} 
	return 0;
}
/*
输出结果:
1 2 3
*/

map

map由红黑树实现,其元素都是"键值/实值"所形成的一个对组(key/value pairs)。每个元素有一个键,是排序准则的基础。每一个键只能出现一次,不允许重复。
map主要用于资料一对一映射的情况,map内部自建一颗红黑树,这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。比如一个班级中,每个学生的学号跟他的姓名就存在着一对一映射的关系。

特点

  • 自动建立Key - value的对应。key和value可以是任意你需要的类型。

  • 根据key值快速查找记录,查找的复杂度基本是O(logN),如果有1000个记录,二分查找最多查找10次(1024)。

  • 增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。

  • 对于迭代器来说,可以修改实值,而不能修改 key。

例子

#include "stdafx.h"
#include <iostream>
#include <map>
#include <string>

using namespace std;

int main(int argc, char* argv[])
{
	map<int, string> mapTemp;

	mapTemp.insert({ 5,"张三" });
	mapTemp.insert({ 3, "李四"});
	mapTemp.insert({ 4, "隔壁老王" });

	map<int, string>::iterator it;
	for (it = mapTemp.begin(); it != mapTemp.end(); it++)
	{
		printf("学号:%d 姓名:%s\n", (*it).first, (*it).second.c_str());
	}

	return 0;
}

/*
输出结果:
学号:3 姓名:李四
学号:4 姓名:隔壁老王
学号:5 姓名:张三
*/

总结

待续。。。。。。。。

posted @ 2020-08-01 11:56  Treasure_lee  阅读(368)  评论(0)    收藏  举报