STL——标准模板库

STL——标准模板库

1、容器

容器类是管理序列的类,是容纳一组对象或对象集的类。通过由容器类提供的成员函数,可以实现诸如向序列中插入元素,删除元素,查找元素等操作,这些成员函数通过返回迭代子来指定元素在序列中的位置。

(1)、顺序容器

vector  矢量容器    底层实现:不定长顺序表    #include  支持随机迭代器

list  双向链表容器  底层实现:双向循环链表  #include  支持双向迭代器

dquen  双端队列容器  底层实现:双端队列  #include  支持随机迭代器

template
void Show(Container& con)
{
	Container::iterator it = con.begin();
	while (it != con.end())
	{
		std::cout << *it << " ";
		it++;
	}
	std::cout << std::endl;
}
#include

int main()
{
	std::deque dqu;
	for (int i = 0; i < 10; i++)
	{
		dqu.push_front(i + 1);
	}
	Show(dqu);

	dqu.erase(dqu.end() - 3);
	Show(dqu);
	dqu.sort();
	return 0;
}
#if 0
#include
int main()
{
	std::list lst;
	for (int i = 0; i < 10; i++)
	{
		lst.push_front(i + 1);
	}
	Show(lst);
	lst.pop_front();
	Show(lst);

	lst.erase(++++lst.begin());
	Show(lst);
	//std::sort(lst.begin(), lst.end());
	lst.sort();
	Show(lst);
	return 0;
}

#include

int main()
{
	std::vector> vec;
	std::vector ivec1;
	std::vector ivec2;
	vec.push_back(ivec1);
	vec.push_back(ivec2);

	std::vector> vec2(10);
	vec2[0].push_back(1);
	std::cout << vec2[0][0] << std::endl;
	return 0;
}

int main()
{
	std::vector vec1;
	std::vector vec2(10);
	std::vector vec3(10, 20);
	int arr[] = { 123, 2, 3456, 7 };
	int len = sizeof(arr) / sizeof(arr[0]);
	std::vector vec4(arr, arr + len);
	//Show(vec4);

	for (int i = 0; i < 10; i++)
	{
		vec1.push_back(i + 1);
	}
	Show(vec1);
	vec1.insert(vec1.begin() + 5,100);
	Show(vec1);
	std::sort(vec1.begin(), vec1.end());
	Show(vec1);
	vec1.pop_back();
	vec1.erase(vec1.end() - 2);
	Show(vec1);

	std::cout << vec1.front() << std::endl;
	std::cout << vec1.back() << std::endl;
	return 0;
}

(2)、关联容器(红黑树(RBT)、支持双向迭代器 )

set  单重集合  不允许键值重复  #include

multiset  多重集合  #include

map  单重映射  存放键值(key-value)对  #include

multimap  多重映射   #include

#include 
#include 
#include 
/*
	map
		key-value   
*/

int main()
{
	std::map mymap;
	//std::cout << typeid(std::map::value_type).name() << std::endl;
	
	std::pair p1(1, 11);
	mymap.insert(p1);
	mymap.insert(std::pair(2, 22));

	std::map::iterator it = mymap.begin();
	while (it != mymap.end())
	{
		std::cout << it->first << " ==> " << it->second << std::endl;
		it++;
	}
	std::map::iterator fit = mymap.find(1);//基于key查询
	//Show(mymap);

	mymap[3] = 33;
	
	return 0;
}

int main()
{
	int arr[] = { 1, 32, 11, 543, 12, 9, 8, 234, 23 };
	int len = sizeof(arr) / sizeof(arr[0]);
	//std::set myset(arr, arr + len);

	std::set myset;
	myset.insert(10);
	myset.insert(arr, arr + len);
	Show(myset);
	myset.erase(1000);
	Show(myset);

	std::set::iterator fit = std::find(myset.begin(), myset.end(), 10);
	std::set::iterator fit1 = myset.find(11);//O(log2  n)

	int count = myset.count(10);
	std::cout << count << std::endl;
	myset.insert(10);
	count = myset.count(10);
	std::cout << count << std::endl;
	return 0;
}

(3)、容器适配器(默认存放的是deque、不支持迭代器)  

可以象顺序容器一样使用。但是它没有自己的构造和析构函数,它使用其实现类(如vector)的构造和析构函数。队列(queue)缺省用deque为基础,栈(stack)可用vector或deque为基础。

STL——标准模板库_第1张图片

stack  栈  #include

quene  队列  #include

priority_queue(优先级队列):实现优先级队列。元素插入是自动按优先级顺序插入,使最高优先级元素首先从优先级队列中取出。常用矢量为基础容器。缺省时priority_queue用vector为基础数据结构。 

STL——标准模板库_第2张图片

标准库容器类

说明

顺序容器

vector(参量)

deque(双端队列)

list(列表)

 

从后面快速插入与删除,直接访问任何元素

从前面或后面快速插入与删除,直接访问任何元素

从任何地方快速插入与删除,双链表

关联容器

set(集合)

multiset(多重集合)

map(映射)

multimap(多重映射)

 

快速查找,不允许重复值

快速查找,允许重复值

一对一映射,基于关键字快速查找,不允许重复值

一对多映射,基于关键字快速查找,允许重复值

容器适配器

stack(栈)

queue(队列)

priority_queue

(优先级队列)

 

后进先出(LIFO

先进先出(FIFO

最高优先级元素总是第一个出列

2、泛型算法

泛型算法不依赖于具体的容器,通用的算法更易于扩充。泛型算法中采用函数对象(function object)引入不同情况下同一算法的差异。它没有使用继承和多态,避免了虚函数的开销,使STL效率更高。

STL最大的优点是提供能在各种容器中通用的算法,例如插入、删除、查找、排序等等。

  STL提供70种左右的标准算法。算法只是间接通过迭代子操作容器元素。

  算法通常返回迭代子。一个算法通常可用于多个不同的容器,所以称为泛型算法(generic algorithm)

算法分为:

1.修改容器的算法,即变化序列算法(mutating-sequence algorithm),如copy()remove()replace()swap()

2.不修改容器的算法,即非变化序列算法(non-mutating-sequence algorithm),如count()find()等。

3.数字型算法。 

泛型算法分以下几类:

1.查找算法:有13种查找算法用各种策略去判断容器中是否存在一个指定值。equal_range()lower_bound()upper_bound()提供对半查找形式。

2.排序和通用整序算法:共有14种排序(sorting)和通用整序(ordering)算法,为容器中元素的排序提供各种处理方法。所谓整序,是按一定规律分类,如分割(partition)算法把容器分为两组,一组由满足某条件的元素组成,另一组由不满足某条件的元素组成。

3.删除和代替算法:有15种删除和代替算法。

4.排列组合算法:有2种算法。排列组合是指全排列。如:三个字符{abc}组成的序列有6种可能的全排列:abcacbbacbcacabcba;并且六种全排列按以上顺序排列,认为abc最小,cba最大,因为abc是全顺序(从小到大)而cba是全逆序(从大到小)。  

5.生成和改变算法:有6种,包含生成(generate),填充(fill)等等。

6.关系算法:有7种关系算法,为比较两个容器提供了各种策略,包括相等(equal()),最大(max()),最小(min())等等。 

7.集合算法4种集合(set)算法提供了对任何容器类型的通用集合操作。包括并(union),交(intersection),差(difference)和对称差(symmetric difference)。

STL——标准模板库_第3张图片

8.堆算法:有4种堆算法。堆是以数组来表示二叉树的一种形式。标准库提供大根堆(max_heap),它的每个结点的关键字大于其子结点的关键字。

9.算术算法:该类算法有4种,使用时要求包含头文件

3、迭代器

迭代器是面向对象版本的指针,它提供了访问容器或序列中每个对象的方法。这样就可以把算法用于容器所管理的序列。

(1)、C++标准库中有五种预定义迭代器,其功能最强最灵活的是随机访问迭代器。

STL——标准模板库_第4张图片

STL——标准模板库_第5张图片

(2)、功能型
            1.反向迭代器
            2.插入型迭代器  back_insert_iterator、front_insert_iterator、insert_iterator

               类中  push_back、push_front、insert  

            3.流式迭代器      istream_iterator、ostream_iterator 

结合find()算法讨论迭代子与泛型算法的关系。find()定义如下:

template<typename InputIterator,typename T >

InputIterator find(InputIterator first, InputIterator last,

     const T value ){

   for(;first!=last;++first)  if(value==*first) return first;

   return last}

 可见,泛型算法不直接访问容器的元素,与容器无关。元素的全部访问和遍历都通过迭代子实现。并不需要预知容器类型。

STL——标准模板库_第6张图片

#include


int main()
{
	int arr[] = { 21, 34, 58, 675 };
	int len = sizeof(arr) / sizeof(arr[0]);
	std::vector vec(arr, arr + len);
//	std::copy(vec.begin(), vec.end(), std::ostream_iterator(std::cout," "));
	std::vector vec1;
	std::copy(std::istream_iterator(std::cin), std::istream_iterator(), std::back_insert_iterator>(vec1));
	Show(vec1);
	return 0;
}

int main()
{
	int arr[] = { 21, 34, 58, 675 };
	int len = sizeof(arr) / sizeof(arr[0]);
	std::vector vec(arr, arr+ len);
	
	std::vector::iterator iit = vec.begin();
	*iit = 20;
	Show(vec);
	std::back_insert_iterator> bii(vec);
	*bii = 20;
	Show(vec);
	return 0;
}

int main()
{
	int arr[] = { 21, 34, 58, 675 };
	int len = sizeof(arr) / sizeof(arr[0]);
	std::vector vec(arr, arr+ len);

	std::vector::reverse_iterator eit = vec.rbegin();
	while (eit != vec.rend())
	{
		std::cout << *eit << " ";
		eit++;
	}
	std::cout << std::endl;
	return 0;
}

4、函数对象(仿函数) #include

函数对象(function object)的概念与使用使算法摆脱了对不同类型数据个性操作的依赖

在C++中,为了使程序的安全性更好,采用“引用”来代替指针作为函数的参数或返回值。在C++的泛型算法中类似地采用了“函数对象”(function object)来代替函数指针。函数对象是一个类,它重载了函数调用操作符(operator())。该操作符封装了应该被实现为一个函数的操作。典型情况下,函数对象被作为实参传递给泛型算法。和“引用”一样,“函数对象”独立使用比较少。函数对象亦称拟函数对象(function_like object)和函子(functor)。

函数对象与函数指针相比较有三个优点:第一,函数指针是间接引用,不能作为内联函数,而函数对象可以,这样速度更快;第二,函数对象可以拥有任意数量的额外数据,用这些数据可以用来缓冲当前数据和结果,提高运行质量,当然多数情况下不一定使用,上例中res就是一个额外数据;第三,编译时对函数对象作类型检查。

函数对象有多种来源:
1. 标准库预定义的一组算术,关系和逻辑函数对象;
2. 预定义的一组函数适配器,允许对预定义的函数对象进行特殊化或扩展;
3. 自定义函数对象。

operator()()
 一元函数对象
 二元函数对象 

5、适配器

容器适配器
函数适配器

和容器类一样,函数对象也可以由函数适配器来特殊化或扩展一元(单参数)或二元(双参数)函数对象:

1.绑定器(binder):把二元函数对象中的一个参数固定(绑定),使之转为一元函数,C++标准库提供两种预定义的binder适配器:bind1st和bind2nd,分别绑定了第一或第二个参数。

2.取反器(negator):把函数对象的值翻转的适配器,如原来为小于,用了它后就变成了大于。C++标准库也提供了两种negator适配器:not1和not2。not1用于一元预定义函数对象;not2用于二元预定义函数对象。 

6、空间配置器

对象的生成和销毁分离开来

在STL当中,allocator将这四个部分分别拆开,分别对应于alloc::allocate(), ::construct(), ::destroy(), alloc::deallocate(),

一级空间配置器:对(malloc、free)封装,(开辟内存足够大,大于128bt)

二级空间配置器:内存池的实现。(16个自由链表)

如果仅仅只有第一层配置器的话,会造成太多内存碎片。在第二级配置的过程中,每次会配置一大块内存,并维护对应的自由链表,若下次再有相同大小的内存需求,就直接从free-list中拨出;如果释放小额区块,则收到对应的free-list当中去。

STL为了提高效率,在空间的配置上设置了双层配置器,第一级就是使用传统的malloc()和free(), 第二级配置器则视情况采用不同的策略:当申请空间超过128bytes时,调用第一级配置器;当申请空间小于128bytes时,采用memory pool整理方式,而不是一味的求助于第一级配置器,其中,memory pool由malloc()配置而得。具体如下图所示:

STL——标准模板库_第7张图片

 

当分配空间的时候,查找到free-list对应的下标,接下来就是链表删除的操作了

当返还空间的时候,查到free-list对应的下标,接下来就是链表的插入操作了

当allocate()发现free-list当中没有可用区块时,就调用refill()为其填充空间,新的空间来自内存池,默认获取20个新节点;若空间不足,获取节点个数可能会小于20;若内存池中剩余空间不足所1个申请的区块的大小,则先将剩余空间(若有)编入对应free-list,之后配置heap空间,申请40个对应区块大小+round_up(heap_size>>4)字节的内存,作为内存池容量。若分配失败,则有如下几种选择:1. 查看free-list中足够大的区块是否有尚未使用的空间;2. 调用第一级配置器,抛出异常。

STL——标准模板库_第8张图片

 

 

 

 

你可能感兴趣的:(C++,C++)