c++ - 第11节 - stack和queue类

目录

1.标准库中的stack类

1.1.stack类

1.2.stack类的常用接口说明

1.3.stack类练习题

1.4.stack类的模拟实现

2.标准库中的queue类

2.1.queue类

2.2.queue类的常用接口说明

2.3.queue类的模拟实现

3.标准库中的priority_queue类

3.1.priority_queue类

3.2.priority_queue类的常用接口说明

3.3.priority_queue类的模拟实现

4.deque的简单介绍

5.反向迭代器介绍

5.1.反向迭代器源码分析

5.2.反向迭代器代码实现


1.标准库中的stack

1.1.stack

stack类的文档介绍:https://cplusplus.com/reference/stack/stack/?kw=stack

注:

1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作
4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。

5.下图所示是官方库中链表list、栈stack、队列queue的声明和栈stack、队列queue的介绍。严格地说,list是一种容器,而stack和queue是一种容器适配器,从下图可以看出,链表list声明的第二个参数是一个空间配置器,栈stack和队列queue的第二个参数是一个容器

栈stack、队列queue(包括后面的priority_queue)是容器适配器,也就是说他们不是自己原生实现的,他们是依靠包装容器适配出来的

1.2.stack类的常用接口说明

使用stack前的说明:

1.使用stack类需要包含stack的头文件,代码为:#include<stack>

注:这里不是包含stack.h是因为会和c语言的库函数冲突,不能直接包含stack.cpp是因为如果项目里面同时两个人都包含stack.cpp,那么就会造成重定义

2.stack类是在std里面的,因此使用stack类需要using namespace std将std展开(如果不展开每次使用stack类需要std::stack)

注:std和iostream是无关的,只不过帮助进行输入输出的cout、cin、enl等是在std里面定义的。如果不输入输出,不包含iostream也可以使用stack类,但是需要展开std

stack的接口:

函数名称

功能说明

stack()
构造空的栈
empty()
检测stack是否为空
size()
返回stack中元素的个数
top()
返回栈顶元素的引用
push()
将元素val压入stack中
pop()
将stack中尾部的元素弹出

注:

1.stack里面没有迭代器,因为栈这种数据结构让你随便去遍历反而是不好的,如果随便遍历就保证不了后进先出的功能了,栈里面数据的遍历代码如下图所示

1.3.stack类练习题

练习题一:

题目描述:

题目链接:155. 最小栈 - 力扣(LeetCode)

思路:

思路1:建立两个栈st和minst,st是正常的栈存储数据,minst存储最小值数据。插入时插入到st栈中,插入的值如果大于minst栈top的值,则minst栈再插入top的值,插入的值如果小于minst栈top的值,则minst栈插入st栈插入的值。st栈pop删除数据的时候,minst也跟着删除数据。

例如:st插入5,目前最小值是5,则minst插入5;st插入8,目前最小值是5,则minst再插入5;st插入7,目前最小值是5,则minst再插入5;st插入2,目前最小值是2,则minst插入2,如下图一所示,st进行删除,那么minst也要进行删除,如下图二所示。像前面的操作如果想要得到栈的最小值,直接取minst的的top即可。

  

上面的思路可以优化一下,见下面思路2。

思路2:建立两个栈st和minst,st是正常的栈存储数据,minst存储最小值数据。插入时插入到st栈中,插入的值如果大于minst栈top的值,不做处理,插入的值如果小于minst栈top的值,则minst栈插入st栈插入的值。st栈pop删除数据的时候,如果st删除的数据大于minst栈top的值,不做处理,如果st删除的数据等于minst栈top的值(不存在st删除的数据大于minst栈top的值的情况),minst也跟着删除数据,如下图所示。

代码:

练习题二:

题目描述:

题目链接:栈的压入、弹出序列_牛客题霸_牛客网 (nowcoder.com)

思路:

入栈序列先入栈,每次入栈以后,栈顶跟出栈序列比较,有两种情况:

情况一:能匹配:出栈序列往后,出战。

情况二:不能匹配:有两种情况:(1)如果入栈序列没有走到尾,说明这个数据可能还没入栈,继续入栈(2)如果入栈序列已经走到尾,说明数据一定在栈中,只是顺序不对,出栈序列非法

例1:输入[1 2 3 4 5]和[4 5 3 2 1]序列

出栈序列指向4,入栈序列入栈1,和出栈序列4不匹配,入栈序列入栈2,和出栈序列4不匹配,入栈序列入栈3,和出栈序列4不匹配,入栈序列入栈4,和出栈序列4匹配,出栈序列指向5,入栈序列3,和出栈序列5不匹配,入栈序列入栈5,和出栈序列5匹配,出栈序列指向3,入栈序列3,和出栈序列3匹配,出栈序列指向2,入栈序列2,和出栈序列2匹配,出栈序列指向1,入栈序列1,和出栈序列1匹配,出栈序列没问题

例2:输入[1 2 3 4 5]和[4 3 5 1 2]序列

出栈序列指向4,入栈序列入栈1,和出栈序列4不匹配,入栈序列入栈2,和出栈序列4不匹配,入栈序列入栈3,和出栈序列4不匹配,入栈序列入栈4,和出栈序列4匹配,出栈序列指向3,入栈序列3,和出栈序列3匹配,出栈序列指向5,入栈序列2,和出栈序列5不匹配,入栈序列入栈5,和出栈序列5匹配,出栈序列指向1,入栈序列2,和出栈序列1不匹配,入栈序列已经走到尾,出栈序列非法

代码:

注:上面 return popi==popV.size 和 return st.empty() 两种结束条件都是可以的

练习题三:

题目描述:

题目链接:150. 逆波兰表达式求值 - 力扣(LeetCode)

思路:(后缀表达式计算的思路)

从前往后依次取数据:

(1)如果是操作数:将操作数入栈

(2)如果是运算符:取连续两个栈顶数据进行运算,运算结果继续入栈

数据走完将栈里的操作数出栈,出栈的值就是结果值

例:计算后缀表达式123*+的结果

首先遇到数据1,1是操作数将1入栈,此时栈里的数据为1,走到数据2,2是操作数将2入栈,此时栈里的数据为12,走到数据3,3是操作数将3入栈,此时栈里的数据为123,走到数据*,*是运算符,取连续两个栈顶数据3和2进行运算,结果为2*3=6(连续出两个先出来的是运算符的右操作数,后出来的是运算符的左操作数),将结果6入栈,此时栈里的数据为16,走到数据+,+是运算符,取连续两个栈顶数据6和1进行运算,结果为6+1=7,将7入栈,数据取完将栈里面操作数出栈就是结果,结果为7

代码:

注:

1.中缀表达式就是操作符在中间,后缀表达式就是操作符在后面(我们平时写的都是中缀表达式)

中缀表达式1+2*3转化为后缀表达式就是123*+,后缀表达式123*+的意思就是2和3相乘,然后1加上2和3相乘的结果。本题是给你后缀表达式,让你计算出结果。

2.本题是后缀表达式计算的问题。还有道题是中缀表达式计算的问题,中缀表达式计算问题的解法是先将中缀表达式转成后缀表达式,将计算后缀表达式的值即可,后缀表达式的计算问题我们已经会了,将中缀表达式转成后缀表达式的思路如下所示

思路:(中缀表达式转成后缀表达式的思路)

从前往后依次取数据:

(1)遇到操作数:将操作数输出或者存储(输出还是存 储是看转成后的表达式输出还是存储)

(2)遇到运算符:跟栈顶运算符进行比较,如果栈为空或者比栈顶运算符优先级高就将其入栈,然后再往下取数据;如果比栈顶运算符优先级低或者优先级一样就出栈顶的操作符,然后继续和此时栈顶运算符比较......

数据走完将栈里的运算符依次出栈

例:将中缀表达式1+2*3/2-5转成后缀表达式

首先遇到数据1,1是操作数进行存储,存储空间此时为1,走到数据+,+是运算符,此时栈为空运算符+入栈,走到数据2,2是操作数进行存储,存储空间此时为12,走到数据*,*是运算符,*运算符比栈顶+运算符优先级高,运算符*入栈,走到数据3,3是操作数进行存储,存储空间此时为123,走到数据/,/是运算符,/运算符和栈顶*运算符优先级相同,此时栈顶运算符*出栈,存储空间此时为123*,/运算符继续和此时栈顶运算符+比较,/运算符优先级高,运算符/入栈,走到数据2,2是操作数进行存储,存储空间此时为123*2,走到数据-,-是运算符,-运算符比栈顶/运算符优先级低,此时栈顶运算符/出栈,存储空间此时为123*2/,-运算符继续和此时栈顶运算符+比较,-运算符和+运算符优先级相同,此时栈顶运算符+出栈,存储空间此时为123*2/+,走到数据5,5是操作数进行存储,存储空间此时为123*2/+5,数据取完将栈里面运算符出栈,存储空间此时为123*2/+5-

3.switch语句case的后面不能跟字符串,系统会报错,如果本题判断操作数和运算符时一定要使用switch语句case后面要取字符串的第一个字符,例如取"-"第一个字符,但是这样"-"和"-5"就无法区分了,还得再用字符串长度来区分,较麻烦,所以此处我们使用if语句。if语句中操作数和运算符已经区分开了("-"和"-5"已经区分开了),我们使用switch语句来区分"+"、"-"、"*"、"/"

1.4.stack类的模拟实现

test.cpp文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <deque>
#include <functional>
#include <assert.h>
using namespace std;

#include "Stack.h"


int main()
{
	bit::test_stack();

	return 0;
}

stack.h文件:

#pragma once

namespace bit
{
	template<class T, class Container = deque<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_back();
		}

		const T& top()
		{
			return _con.back();
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};


	void test_stack()
	{
		stack<int> s;
		//stack<int, vector<int>> s;
		//stack<int, list<int>> s;
		//stack<int, string> s; 

		s.push(1);
		s.push(2);
		s.push(3);
		s.push(4);
		s.push(300);

		while (!s.empty())
		{
			cout << s.top() << " ";
			s.pop();
		}
		cout << endl;
	}
}

注:

1.前面我们讲过栈stack是一种适配器,适配器的主要作用就是转换,栈stack的功能是实现后进先出功能,实现该功能没必要自己造轮子去实现,可以使用顺序表vector、链表list等很多数据结果去实现,stack类模板的第二个参数是容器Container,给Container参数传什么数据结构就使用该数据结构实现栈stack后进先出的功能。第二个参数有缺省值deque,如果不传该参数默认使用deque这种数据结构来实现栈stack的功能。

deque的声明如下图所示,deque这种容器适合头尾插入删除(链表的优点),还支持operator[ ]随机访问(vector的优点),既有vector的优点也有list的优点,但是deque也有自己的缺点,具体我们后面会讲

2.栈stack的成员变量是使用容器Container来定义的自定义对象,该对象用其自己的构造函数、拷贝构造函数、析构函数即可。我们栈stack里面不写这些函数,编译器会自动生成默认的构造函数、拷贝构造函数、析构函数,自动生成默认的函数对于这里自定义类型的对象就会去调用其本身的函数

3.栈stack里面的入栈push函数、出栈pop函数、查看栈顶元素top函数都可以复用容器Container数据结构的函数来完成,这里复用的函数最好使用各个容器都有的函数以适配各种容器

4.如下图所示,栈stack可以适配deque来实现、可以适配vector来实现、可以适配list来实现。栈stack可以适配string来实现,但是string类里面无法存储大于127的值,存在截断数据丢失的风险


2.标准库中的queue

2.1.queue

queue类的文档介绍:https://cplusplus.com/reference/queue/queue/

注:

1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
   empty:检测队列是否为空
   size:返回队列中有效元素的个数
   front:返回队头元素的引用
   back:返回队尾元素的引用
   push_back:在队列尾部入队列
   pop_front:在队列头部出队列
4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

2.2.queue类的常用接口说明

使用queue前的说明:

1.使用queue类需要包含queue的头文件,代码为:#include<queue>

注:这里不是包含queue.h是因为会和c语言的库函数冲突,不能直接包含queue.cpp是因为如果项目里面同时两个人都包含queue.cpp,那么就会造成重定义

2.queue类是在std里面的,因此使用queue类需要using namespace std将std展开(如果不展开每次使用queue类需要std::queue)

注:std和iostream是无关的,只不过帮助进行输入输出的cout、cin、enl等是在std里面定义的。如果不输入输出,不包含iostream也可以使用queue类,但是需要展开std

queue的接口:

函数名称

功能说明

queue()
构造空的队列
empty()
检测队列是否为空,是返回true,否则返回false
size()
返回队列中有效元素的个数
front()
返回队头元素的引用
back()
返回队尾元素的引用
push()
在队尾将元素val入队列
pop()
将队头元素出队列

注:

1.queue里面没有迭代器,因为队列这种数据结构让你随便去遍历反而是不好的,如果随便遍历就保证不了先进先出的功能了,队列里面数据的遍历代码如下图所示

2.3.queue类的模拟实现

test.cpp文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <deque>
#include <functional>
#include <assert.h>
using namespace std;

#include "Queue.h"


int main()
{
	bit::test_queue();

	return 0;
}

queue.h文件:

#pragma once

namespace bit
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_front();
		}

		const T& front()
		{
			return _con.front();
		}

		const T& back()
		{
			return _con.back();
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};

	void test_queue()
	{
		queue<int> q;
		//queue<int, list<int>> q;
		//queue<int, vector<int>> q; 
		//queue<int, string> q;

		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);

		while (!q.empty())
		{
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;
	}
}

注:

1.队列queue和栈stack相同也是一种适配器,如下图所示,队列queue类模板的第二个参数是容器Container,给Container参数传什么数据结构就使用该数据结构实现队列queue先进先出的功能。第二个参数有缺省值deque,如果不传该参数默认使用deque这种数据结构来实现队列queue的功能。

2.队列queue和栈stack都是适配器,但是有两点不同:

(1)队列queue不能适配vector,因为queue要实现先进先出功能,出栈的时候要进行头删,vector头删效率很低并且其没有pop_front头删函数。

(2)栈stack可以适配string但是存在截断的风险,队列queue不能适配list,除了存在截断数据丢失的风险,最主要的原因也是string头删效率很低并且其没有pop_front头删函数。

3.如下图所示,队列queue可以适配deque来实现、可以适配list来实现。队列queue不能适配string和vector来实现。


3.标准库中的priority_queue

3.1.priority_queue

priority_queue类的文档介绍:https://cplusplus.com/reference/queue/priority_queue/

注:

1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
   empty():检测容器是否为空
   size():返回容器中有效元素个数
   front():返回容器中第一个元素的引用
   push_back():在容器尾部插入元素
   pop_back():删除容器尾部元素
5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

3.2.priority_queue类的常用接口说明

使用priority_queue前的说明:

1.使用priority_queue类需要包含queue的头文件,代码为:#include<queue>,

注:priority_queue类的定义是在queue头文件里的

2.priority_queue类是在std里面的,因此使用priority_queue类需要using namespace std将std展开(如果不展开每次使用priority_queue类需要std::priority_queue)

注:std和iostream是无关的,只不过帮助进行输入输出的cout、cin、enl等是在std里面定义的。如果不输入输出,不包含iostream也可以使用priority_queue类,但是需要展开std

3.优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。
注意:默认情况下priority_queue是大堆。

priority_queue的接口:

函数名称

功能说明

priority_queue()  priority_queue(first, last)
构造一个空的优先级队列
empty( )
检测优先级队列是否为空,是返回true,否则返回false
top( )
返回优先级队列中最大(最小元素),即堆顶元素
push(x)
在优先级队列中插入元素x
pop()
删除优先级队列中最大(最小)元素,即堆顶元素

注:

1.priority_queue优先级队列官方库里的声明和介绍如下图所示,priority_queue模板第二个参数的默认值vector,也就是说默认使用vector作为其底层存储数据的容器

priority_queue优先级队列第三个参数默认传的是仿函数less,传less其实是一个大堆(正常传greater才应该是大堆,这里是c++的一个失误),也就是说priority_queue优先级队列默认取的是大堆。如果想控制成小堆,优先级队列模板中第三个参数传greater仿函数即可。

2.priority_queue里面没有迭代器,因为堆这种数据结构让你随便去遍历反而是不好的,如果随便遍历就保证不了堆的功能了,优先级队列(堆)里面数据的遍历代码如下图所示

优先级队列默认情况下是一个大堆,如上图所示,如果要使用小堆,应该手动传priority_queue优先级队列模板的第二第三个参数,如下图所示

3.3.priority_queue类的模拟实现

模拟实现一:传仿函数实现的版本

test.cpp文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <deque>
#include <functional>
#include <assert.h>
using namespace std;

#include "Priority_queue.h"


int main()
{
	bit::test_priority_queue();

	return 0;
}

Priority_queue.h文件:

#pragma once

namespace bit
{
	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y) const
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y) const
		{
			return x > y;
		}
	};

	// 优先级队列 -- 大堆 <  小堆 >
	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		void AdjustUp(int child)
		{
			Compare comFunc;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (_con[parent] < _con[child])
				if (comFunc(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);

			AdjustUp(_con.size() - 1);
		}

		void AdjustDown(int parent)
		{
			Compare comFunc;
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//if (child+1 < _con.size() && _con[child] < _con[child+1])
				if (child + 1 < _con.size() && comFunc(_con[child], _con[child + 1]))
				{
					++child;
				}

				//if (_con[parent] < _con[child])
				if (comFunc(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void pop()
		{
			assert(!_con.empty());
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();

			AdjustDown(0);
		}

		const T& top()
		{
			return _con[0];
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}

	private:
		Container _con;
	};

	void test_priority_queue()
	{
		/*less<int> LessCom;
		cout << LessCom(1, 2) << endl;

		greater<int> GreaterCom;
		cout << GreaterCom(1, 2) << endl;*/

		//priority_queue<int> pq;
		priority_queue<int, vector<int>, greater<int>> pq;

		pq.push(2);
		pq.push(5);
		pq.push(1);
		pq.push(6);
		pq.push(8);

		while (!pq.empty())
		{
			cout << pq.top() << " ";
			pq.pop();
		}
		cout << endl;
	}

}

注:

1.优先级队列priority_queue和队列queue、栈stack相同也是一种适配器,如下图所示,优先级队列priority_queue类模板的第二个参数是容器Container,给Container参数传什么数据结构就使用该数据结构实现优先级队列priority_queue堆的功能。第二个参数有缺省值vector,如果不传该参数默认使用vector这种数据结构来实现优先级队列priority_queue的功能。

因为堆这种数据结构要进行数据随机访问并且要在中间插入删除数据,所以这里默认值给的是vector是因为vector适合随机访问数据并且比deque更适合在中间插入删除数据。deque适合在头尾插入删除,但是deque随机访问效率不高,且不适合在中间插入删除数据

2.优先级队列priority_queue插入数据时,调用容器的尾插函数插入之后,此时优先级队列就不是一个堆了,还需要向上调整算法,将此时的优先级队列变成堆。优先级队列priority_queue插入数据代码和向上调整算法(大堆的向上调整算法)如下图所示。这里可以看出优先级队列priority_queue插入数据的时间复杂度为log_{2}^{n}

  

3.优先级队列priority_queue删除数据时,删除的是堆顶数据(二叉树的根节点),也就是优先级队列第一个数据,首先将堆顶数据和最后一个数据进行交换,然后调用容器的尾删函数进行删除,此时优先级队列不是一个堆了,还需要向下调整算法,将此时的优先级队列变成堆。优先级队列priority_queue删除数据代码和向下调整算法(大堆的向下调整算法)如下图所示,这里可以看出优先级队列priority_queue删除数据的时间复杂度为log_{2}^{n}

4.这里我们是自己实现了向上向下调整算法,其实算法库algorithm里面,有库里面的入堆函数push_heap(核心是向上调整算法)、出堆函数pop_heap(核心是向下调整算法)、建堆函数make_heap、堆排序函数sort_heap、判断是不是堆函数is_heap,如下图所示

5.返回堆顶元素top函数官方库里的声明如下图所示,value_type就是类模板中的参数T,也就是说top函数的返回类型是const T&类型,这里采用引用返回是为了避免传值返回拷贝构造,提高效率,但是采用引用返回外面就可以修改堆顶的数据了,如果外面可以修改堆顶的数据是一件很危险的事情,外面将堆顶修改了那么堆很可能就不再是一个堆了,所以引用返回还要使用const进行修饰

6.仿函数(函数对象)介绍:仿函数(函数对象)其实是一个对象,对象对应的类里面对小括号进行重载。平时小括号的使用方式有两个,一个是(表达式),其作用是加强优先级和类型强转,另一个是函数名(形参表),其作用是辅助进行函数的调用。仿函数对应的类里面对小括号进行重载重载的其实是函数名(形参表)里面的小括号,如下图所示就是仿函数对应的类less的实现代码。

此时less就是一个类型,可以使用less定义出对象,定义出来的对象就叫做仿函数或函数对象,使用less类的方式如下图所示,可以用less来比较大小。LessCom是一个less类型的对象,因为LessCom的使用方式就好像函数一样,所以称LessCom这种对象为函数对象或仿函数

上面的less类定义出来的仿函数只能比较整型,利用模板的知识我们对上面的less类进行改进,如下图所示,其中形参x和y前面用const修饰是为了接收const类型的变量,支持对const类型的变量进行比较

除了less类,还有一个类叫做greater,less类定义出的对象可以进行小于的比较,greater类定义出的对象可以进行大于的比较,greater类代码如下图一所示,使用代码如下图二所示

7.前面的优先级队列priority_queue代码我们是写死实现的大堆,无法实现小堆。解决办法是使用仿函数,在优先级队列priority_queue的模板中再加一个参数,如下图一所示,仿函数的类型也是一种类型,既然是类型我们就可以当作参数进行传参。官方库中的大堆对应的是小于,less就是小于比较的,所以如果要使用大堆模板第三个参数就传less,官方库中的小堆对应的是大于,greater就是大于比较的,所以如果要使用小堆模板第三个参数就传greater,如下图二所示可以看出官方库中优先级队列priority_queue的声明第三个参数默认传的是less,所以如果不传第三个参数,默认是大堆

注意:官方库中是有less和greater仿函数类的,下图二所示的优先级队列声明用的就是官方库中的仿函数类,要使用官方库中的less和greater这些仿函数需要包含functiona头文件,代码为#include<functional>

在优先级队列priority_queue中,我们使用仿函数来进行比较即可,向上调整算法如下图所示,如果要使用大堆传的是less,这里comFunc仿函数就是比较小于的,实现的就是大堆的向上排序算法;如果要使用小堆传的是greater,这里comFunc仿函数就是比较大于的,实现的就是小堆的向上排序算法。

向下调整算法如下图所示,如果要使用大堆传的是less,这里comFunc仿函数就是比较小于的,实现的就是大堆的向下排序算法;如果要使用小堆传的是greater,这里comFunc仿函数就是比较大于的,实现的就是小堆的向下排序算法。

模拟实现二:既可以传仿函数也可以传函数指针实现的版本

test.cpp文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <deque>
#include <functional>
#include <assert.h>
using namespace std;

#include "Priority_queue.h"

namespace std
{
	// 商品
	struct Goods
	{
		string _name;
		double _price;
		size_t _saleNum;
		//...

		/*bool operator<(const Goods& g) const
		{
			return _price < g._price;
		}*/
	};

	struct LessPrice
	{
		bool operator()(const Goods& g1, const Goods& g2) const
		{
			return g1._price < g2._price;
		}
	};

	struct GreaterPrice
	{
		bool operator()(const Goods& g1, const Goods& g2) const
		{
			return g1._price > g2._price;
		}
	};

	struct LessSaleNum
	{
		bool operator()(const Goods& g1, const Goods& g2) const
		{
			return g1._saleNum < g2._saleNum;
		}
	};

	struct GreaterSaleNum
	{
		bool operator()(const Goods& g1, const Goods& g2) const
		{
			return g1._saleNum > g2._saleNum;
		}
	};

	void test_functional()
	{
		vector<int> v;
		v.push_back(2);
		v.push_back(1);
		v.push_back(4);
		v.push_back(5);
		v.push_back(3);

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		// less
		sort(v.begin(), v.end());
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		// greater
		sort(v.begin(), v.end(), greater<int>());
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		// 指向数组的原生指针,本身就是天然迭代器
		int a[6] = { 1, 2, 5, 2, 5, 7 };
		sort(a, a + 6);
		sort(a, a + 6, greater<int>());

		Goods gds[4] = { { "苹果", 2.1, 1000}, { "香蕉", 3.0, 200}, { "橙子", 2.2,300}, { "菠萝", 1.5,50} };

		sort(gds, gds + 4, LessPrice());
		sort(gds, gds + 4, GreaterPrice());
		sort(gds, gds + 4, LessSaleNum());
		sort(gds, gds + 4, GreaterSaleNum());
	}
}

int main()
{
	//std::test_functional();
	bit::test_priority_queue2();

	return 0;
}

Priority_queue.h文件:

#pragma once

namespace bit
{
	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y) const
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y) const
		{
			return x > y;
		}
	};

	// 优先级队列 -- 大堆 <  小堆 >
	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		priority_queue(const Compare& comFunc = Compare())
			:_comFunc(comFunc)
		{}

		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last,
			const Compare& comFunc = Compare())
			: _comFunc(comFunc)
		{
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}

			// 建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
			{
				AdjustDown(i);
			}
		}

		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_comFunc(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);

			AdjustUp(_con.size() - 1);
		}

		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//if (child+1 < _con.size() && _con[child] < _con[child+1])
				if (child + 1 < _con.size() && _comFunc(_con[child], _con[child + 1]))
				{
					++child;
				}

				//if (_con[parent] < _con[child])
				if (_comFunc(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void pop()
		{
			assert(!_con.empty());
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();

			AdjustDown(0);
		}

		const T& top()
		{
			return _con[0];
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}

	private:
		Compare _comFunc;
		Container _con;
	};

	bool ComIntLess(int x1, int x2)
	{
		return x1 > x2;
	}

	void test_priority_queue1()
	{
		//priority_queue<int> pq;
		//priority_queue<int, vector<int>, greater<int>> pq;
		priority_queue<int, vector<int>, bool(*)(int, int)> pq(ComIntLess);

		pq.push(2);
		pq.push(5);
		pq.push(1);
		pq.push(6);
		pq.push(8);

		while (!pq.empty())
		{
			cout << pq.top() << " ";
			pq.pop();
		}
		cout << endl;
	}

	void test_priority_queue2()
	{
		int a[] = { 1, 4, 2, 7, 8, 9 };
		priority_queue<int> pq(a, a + 6);
	}
}

注:

1.仿函数的优势:很多场景下,仿函数用来替代函数指针

例如:前面学习过,c语言实现的qsort函数就需要传函数指针,来规定数据的比较方式,其声明如下图所示;如果用c++实现qsort函数就可以直接用仿函数来实现的

这里优先级队列priority_queue如果既想使用仿函数实现又想使用函数指针实现,我们定义一个函数ComIntLess用来进行小于比较,定义一个函数ComIntGreater用来进行大于比较,如下图一所示。优先级队列priority_queue模板第三个参数,如果传的是仿函数的类型,那么在priority_queue类中利用仿函数类型定义一个对象,该对象使用小括号操作符就可以调用自己的成员函数,但是优先级队列priority_queue模板第三个参数如果传的是函数指针类型,在priority_queue类中只有该函数类型是调用不了该函数的。

如下图二中,官方库的priority_queue第一个构造函数第一个参数可以接收一个Compare类型的对象,Compare类型就是模板第三个参数传的类型,其缺省值给的是Compare类型的匿名对象。那么我们实现可以给模板第三个参数Compare传ComIntLess或ComIntGreater的指针类型,然后定义一个Compare类型的成员变量_comFunc,模仿官方库的priority_queue第一个构造函数将ComIntLess或ComIntGreater传参给构造函数,构造函数用const Compare&类型的comFunc来接收,comFunc就是ComIntLess或ComIntGreater函数的别名,使用comFunc初始化_comFunc成员变量那么_comFunc成员变量就指向了ComIntLess或ComIntGreater函数

这样上面Priority_queue.h文件里的代码既可以给模板第三个参数传仿函数类型,用仿函数来实现,构造的时候使用缺省的compare()匿名对象进行构造即可,成员变量_comFunc就是仿函数。同时也可以传函数指针类型,定义的时候将对应的函数传过去通过构造函数使成员变量_comFunc指向该函数。如下图所示,这样既可以传仿函数也可以传函数指针来实现优先级队列priority_queue的堆功能

2.正常情况下优先级队列priority_queue使用库里面的less和greater仿函数就可以了,但是有些情况下必须我们显式的去写仿函数,以c++的sort函数为例。

我们先介绍一下sort函数,下面是官方库中的sort函数声明,使用c++的sort函数必须包含algorithm头文件,代码为#include<algorithm>

官方库sort函数第二个声明中模板第二个参数是compare,此处如果传less就是排升序,如果传greater就是排降序。如果不传第二个参数就是调用sort第一个声明的函数,其默认是传less也就是排升序。sort的用法如下图所示,要排降序传greater需要传greater<int>(),和优先级队列Priority_queue.h里面传greater相比多加了一个小括号,原因是优先级队列是给类模板传参,需要传的是类型,greater<int>就是类型,sort函数是给sort函数的形参传参,需要传的是变量,greater<int>()是定义出的匿名对象,然后sort函数模板根据形参类型来推导模板参数(模板隐式实例化)

如果我们自己去创建一个数组,相对数组里面的数据进行排序,也可以使用sort函数,sort函数的参数要求是迭代器,我们创建的数组将首元素指针和尾元素指针传过去也是可以的,因为如果数据存储是连续的,那么原生指针就是天然的迭代器(vector这种连续存储数据的数据结构其迭代器底层也是指针),如下图所示,注意迭代器传数据要求左闭右开

less和greater仿函数对于内置类型直接使用<或>进行比较,对于自定义类型会去调用对应的自定义类的比较函数operator<或operator>来进行比较,如下图所示

然而自定义类只能重载一个小于比较函数和一个大于比较函数,如上图所示,如果排序增序重载了价格的小于比较函数,那么如果排序完价格还想进行名字或售卖数量的增序排序就不行了,解决办法是不再使用less和greater仿函数,自己定义仿函数来进行对应场景的比较即可,如下图所示

这里通过不同的仿函数来控制sort函数不同的比较逻辑,可以看作是一种更高级的泛型编程

3.优先级队列还有一个构造函数是用迭代器区间进行构造的,其官方声明如下图所示的第二个声明。

这个构造函数在许多场景下使用起来很方便,比如top-k问题可以直接利用该构造函数将前k个数据建立一个k个数的小堆或大堆。该构造函数的实现如下图一所示,该构造函数的使用如下图二所示。


4.deque的简单介绍

虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为栈stack和队列queue只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque容器, priority_queue默认使用vector容器。栈stack、队列queue和优先级队列 priority_queue官方库中的声明如下图所示

总结:

stack可以用deque、vector、list适配,用string适配存在风险

queue可以用deque、list适配,不能用vector、list适配

priority_queue可以用vector、deque适配,但是不推荐用deque

vector特点:

vector的优点:

(1)适合尾插尾删

(2)适合随机访问(vector突出的优点)

(3)CPU高速缓存命中高

vector的缺点:

(1)不适合头部或中部的插入删除(需要挪动数据效率低)

(2)扩容有一定性能消耗,还可能存在一定程度的空间浪费(原因1是删除数据不缩容,原因2是扩容扩少了可能要频繁扩,扩容扩多了就存在空间浪费)

list特点:

list的优点:

(1)任意位置插入删除效率高(时间复杂度为O(1))(list突出的优点)

(2)按需申请释放空间

list的缺点:

(1)不支持随机访问

(2)CPU高速缓存命中低

deque官方库中的声明如下图所示,deque是一个双端队列,是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

开辟多个buffer空间,每个buffer空间固定长度,中控数组(本质是指针数组)指向这些buffer用来将这些buffer空间的链接起来。

当创建第一个buffer时,开辟buffer空间,中控数组中间的元素指向该buffer,从buffer空间开始位置往后存数据;如果进行尾插,不停的尾插导致该buffer数据存满了,那么再创建一个buffer,开辟buffer空间,中控数组最后一个有效元素的下一个元素指向该buffer,从新开辟buffer空间开始位置往后存数据;如果进行头插,开辟buffer空间,中控数组第一个有效元素的上一个元素指向该buffer,从新开辟buffer空间末尾位置往前存数据。

如果中控数组满了,还是需要扩容的,但是扩容的代价很低

这样设计出的deque的特点:

deque的优点:

(1)头部和尾部插入删除数据效率较高

(2)支持随机访问:将要访问的下标值除以一个buffer存储的数据个数得到的结果就是在第几个buffer里面,将要访问的下标值模一个buffer存储的数据个数得到的结果就是要访问的数据是该buffer的第几个元素

(3)扩容的代价小:只需要堆中控数组扩容,中控数组的扩容代价小

(4)CPU缓存命中率高

deque的缺点:

(1)中部的插入删除效率较低:需要挪动数据

(2)虽然支持随机访问,但是效率相比vector而言还是有差距(频繁的随机访问要小心)

结论:deque这种数据结构比较均衡,勉强兼具了vector和list的优点,但是他不像vector和list具有那么极致的优点(vector的极致优点是适合随机访问,vector的极致优点是任意位置插入删除效率高),所以平时用的较少

因为sort排序需要不停的随机访问,并且对于相同的数据sort排序操作是相同的,可以很好的检测不同数据结构随机访问的效率。这里我们就用sort排序来对比vector和deque两种数据结构对于数据任意访问的效率高低

从上图可以看出,vector随机访问的效率要明显高于deque。

如下图所示,如果要对deque的数据进行排序,我们可以先将deque的数据拷贝到vector里面,对vector进行排序然后将排序后的数据拷贝回deque,这样比直接对deque里面数据进行排序效率更高。

注:string、vector、list、deque等类中有一个赋值函数assign函数,deque中的assign函数声明如下图所示,从第一个声明可以看出deque的assign函数支持用一段迭代器区间进行赋值,来取代原本的值

问题:什么场景适合用deque?

答:大量头尾插入删除,不需要或偶尔随机访问的场景,例如栈stack和队列queue就适合使用deque(栈stack和队列queue的尾插使用deque如果要扩容开辟一小段空间即可,不用像vector那样扩容开辟大量空间,也不用像list那样不停的开辟小块空间且deque缓存利用率高,并且很适合头尾插入删除),所以栈和队列将deque作为其默认适配容器。


5.反向迭代器介绍

前面的内容我们只讲了各种数据结构迭代器的实现,并没有讲反向迭代器的实现,因为反向迭代器也是一个适配器模式,这里我们学习了栈stack和队列queue这种适配器,在这里讲可以更好的理解反向适配器的原理和实现

5.1.反向迭代器源码分析

list的反向迭代器源码分析:

我们可以看到库里面list的反向迭代器是借助正向迭代器实现的。反向迭代器和正向迭代器相比,除了++和--时方向相反,其他操作基本一致。

如果每一个数据结构string、vector、list、deque等等要实现一个正向迭代器,就得再实现一个反向迭代器,这样很麻烦。源码的思路是对正向迭代器封装适配一下,生成对应的反向迭代器,上图所示的reverse_iterator类就是用来对正向迭代器进行封装适配的。

那么我们看一下reverse_iterator类的源码,了解是如何进行封装适配的。reverse_iterator类的源码在stl_iterator.h源码库中,如下图所示。

从上图我们可以看出反向迭代器指向某一位置本质其实是使用里面的迭代器成员变量current指向该位置(current指向某一位置其实又是里面的指针指向该位置)。我们定义反向迭代器变量时,代码类似vector<int>::reverse_iterator rit=v.rbegin(),编译器会将该代码转换成vector<int>::reverse_iterator<iterator> rit=v.rbegin,这里是将对应容器的正向迭代器Iterator传给这里reverse_iterator的模板参数,在reverse_iterator的类模板中使用正向迭代器Iterator定义一个成员变量current,然后这里调用拷贝构造函数将v.rbegin返回的反向迭代器(v.rbegin先调用reverse_iterator的构造函数构造一个一个反向迭代器然后将其返回)拷贝给rit,这里拷贝构造的本质是将v.rbegin返回的反向迭代器传给拷贝构造函数的引用形参x,将x里面的迭代器Iterator类型成员变量current构造给rit里面的迭代器Iterator类型成员变量current,这样rit里面的成员变量current指向的位置和v.rbegin返回的反向迭代器里面current指向的位置相同,那么可以说此时反向迭代器rit也指向了v.rbegin返回的位置。

这里operator*运算符重载函数返回的是当前正向迭代器前一个位置的数据,operator++是让迭代器指向当前位置的前一个位置,operator++是让迭代器指向当前位置的后一个位置。

上图所示是list官方库中rbegin和rend函数的源代码,其中rbegin返回的是用end函数构造的反向迭代器,rend返回的是用begin函数构造的反向迭代器,这样是一种对称设计。如下图所示

这样我们用反向迭代器遍历上图list数据,反向迭代器遍历代码如下图所示,rit=v.rbegin(),反向迭代器rit开始指向头节点位置,*rit取的是前一个位置的数据也就是4,++rit,rit指向数据4的位置,依次往后,当++rit后,rit指向数据2的位置,*rit取的是前一个位置的数据也就是1,++rit,rit指向数据1的位置,此时rit=rend()跳出循环遍历结束,这样反向迭代器就从后往前依次便利了list的4321数据

vector的反向迭代器源码分析:

从上图我们可以看出vector反向迭代器和list反向迭代器实现原理相同,也是利用reverse_iterator类对正向迭代器进行封装适配实现的,并且vector类的rbegin返回的是用end函数构造的反向迭代器,rend返回的是用begin函数构造的反向迭代器,和list相同,如下图所示

其实所有的数据结构反向迭代器的实现都和list、vector相同,都是利用reverse_iterator类对正向迭代器进行封装适配实现的,并且所有数据结构都是rbegin返回的是用end函数构造的反向迭代器,rend返回的是用begin函数构造的反向迭代器。

5.2.反向迭代器代码实现

Reverselterator.h文件:

#pragma once

namespace bit
{
	template<class Iterator, class Ref, class Ptr>
	struct Reverse_iterator
	{
		Iterator _it;
		typedef Reverse_iterator<Iterator, Ref, Ptr> Self;

		Reverse_iterator(Iterator it)
			:_it(it)
		{}

		Ref operator*()
		{
			Iterator tmp = _it;
			return *(--tmp);
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		Self& operator++()
		{
			--_it;
			return *this;
		}

		Self& operator--()
		{
			++_it;
			return *this;
		}

		bool operator!=(const Self& s)
		{
			return _it != s._it;
		}
	};
}

List.h文件:

#pragma once
#include <assert.h>
#include "Reverselterator.h"

namespace bit
{
	template<class T>
	struct list_node
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _data;

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(val)
		{}
	};

	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
		Node* _node;

		__list_iterator(Node* node)
			:_node(node)
		{}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			//return &(operator*());
			return &_node->_data;
		}

		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		self operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}

		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}

		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		bool operator==(const self& it)
		{
			return _node == it._node;
		}

	};


	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		// 反向迭代器适配支持
		typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}

		const_iterator end() const
		{
			return const_iterator(_head);
		}

		iterator begin()
		{
			return iterator(_head->_next);
			//return _head->_next;
		}

		iterator end()
		{
			return iterator(_head);
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		list()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

		// lt2(lt1)
		/*list(const list<T>& lt)
		{
		_head = new Node();
		_head->_next = _head;
		_head->_prev = _head;

		for (auto e : lt)
		{
		push_back(e);
		}
		}*/

		void empty_init()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_init();

			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
		}

		// lt2(lt1) -- 现代写法
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		// lt2 = lt1
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		void push_back(const T& x)
		{
			//Node* tail = _head->_prev;
			//Node* newnode = new Node(x);

			 _head       tail  newnode
			//tail->_next = newnode;
			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;

			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		// 插入在pos位置之前
		iterator insert(iterator pos, const T& x)
		{
			Node* newNode = new Node(x);
			Node* cur = pos._node;
			Node* prev = cur->_prev;

			// prev  newnode  cur
			prev->_next = newNode;
			newNode->_prev = prev;
			newNode->_next = cur;
			cur->_prev = newNode;

			return iterator(newNode);
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());

			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			// prev  next
			prev->_next = next;
			next->_prev = prev;
			delete cur;

			return iterator(next);
		}

	private:
		Node* _head;
	};

	void test_list()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::reverse_iterator rit = lt.rbegin();
		while (rit != lt.rend())
		{
			cout << *rit << " ";
			++rit;
		}
		cout << endl;
	}
}

vector.h文件:

#pragma once
#include <assert.h>
#include "Reverselterator.h"

namespace bit
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		// 反向迭代器适配支持
		typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{}

		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(size_t n, const T& val = T())
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{
			reserve(n);
			for (size_t i = 0; i < n; ++i)
			{
				push_back(val);
			}
		}

		vector(int n, const T& val = T())
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{
			reserve(n);
			for (int i = 0; i < n; ++i)
			{
				push_back(val);
			}
		}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstoage, v._endofstoage);
		}

		//vector(const vector& v);
		vector(const vector<T>& v)
			: _start(nullptr)
			, _finish(nullptr)
			, _endofstoage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);
		}

		//vector& operator=(vector v)
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstoage = nullptr;
			}
		}

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		size_t size() const
		{
			return _finish - _start;
		}

		size_t capacity() const
		{
			return _endofstoage - _start;
		}

		void reserve(size_t n)
		{
			size_t sz = size();
			if (n > capacity())
			{
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, size()*sizeof(T));
					for (size_t i = 0; i < size(); ++i)
					{
						tmp[i] = _start[i];
					}

					delete[] _start;
				}

				_start = tmp;
			}

			_finish = _start + sz;
			_endofstoage = _start + n;
		}

		//void resize(size_t n, const T& val = T())
		void resize(size_t n, T val = T())
		{
			if (n > capacity())
			{
				reserve(n);
			}

			if (n > size())
			{
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}

		void push_back(const T& x)
		{
			/*if (_finish == _endofstoage)
			{
				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
			}

			*_finish = x;
			++_finish;*/

			insert(end(), x);
		}

		void pop_back()
		{
			/*if (_finish > _start)
			{
				--_finish;
			}*/
			erase(end() - 1);
		}

		T& operator[](size_t pos)
		{
			assert(pos < size());

			return _start[pos];
		}

		const T& operator[](size_t pos) const
		{
			assert(pos < size());

			return _start[pos];
		}

		iterator insert(iterator pos, const T& x)
		{
			// 检查参数
			assert(pos >= _start && pos <= _finish);

			// 扩容
			// 扩容以后pos就失效了,需要更新一下
			if (_finish == _endofstoage)
			{
				size_t n = pos - _start;

				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);

				pos = _start + n;
			}

			// 挪动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;

			return pos;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);
			iterator it = pos + 1;
			while (it != _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;

			return pos;
		}

		void clear()
		{
			_finish = _start;
		}

	private:
		iterator _start;
		iterator _finish;
		iterator _endofstoage;
	};

	void test_vector()
	{
		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>::reverse_iterator rit = v.rbegin();
		while (rit != v.rend())
		{
			cout << *rit << " ";
			++rit;
		}
		cout << endl;
	}
}

test.cpp文件:

#include<iostream>
#include<list>
#include<vector>
#include<algorithm>
#include<time.h>
using namespace std;

#include"List.h"
#include "vector.h"


int main()
{
	bit::test_list();
	bit::test_vector();

	return 0;
}

注:

1.如下图所示,这里和库里面源代码不同的是reverse_iterator类模板参数我们多写了Ref和Ptr两个参数,这样可以同时实现普通反向迭代器和const反向迭代器(和list类中的普通迭代器、const普通迭代器实现方法相同),库里面reverse_iterator类模板只用Iterator一个模板参数就实现了普通反向迭代器和const反向迭代器的原因是使用了迭代器的萃取技术(萃取技术下一节模板进阶我们会进行讲解)

2.如下图所示是list源代码,源代码中多参数的reverse_bidirectional_iterator类模板和只传迭代器的reverse_iterator类模板都有,旧版本的编译器用的是多参数的reverse_bidirectional_iterator类模板,现在编译器用的是只传迭代器的reverse_iterator类模板。其实不只是list,其他类的源代码也相同

3.以list类为例,如果我们像源代码一样只传正向迭代器给Reverse_iterator的模板参数(不传Ref和Ptr),如下图所示,此时Reverse_iterator里面只有迭代器类型,那么我们面对的挑战是Reverse_iterator里面的operator*和operator->函数返回值没办法表示。

其实标准而言,要符合一个迭代器还需要在迭代器里面定义四种类型,如下图list标准库中迭代器的定义。其中iterator_category是迭代器类型用来标识是哪种类型的迭代器,value_type是T用来标识数据的类型,pointer是Ptr用来标识数据的指针,reference是Ref用来标识数据的引用。

注意:

(1)标准库中所有容器的迭代器里面都有定义这些类型

(2)这里的pointer和reference不一定是value_type*和value_type*&,也就是Ptr和Ref不一定是T*和T&,如果是普通迭代器那么Ptr和Ref是T*和T&,如果是const迭代器那么Ptr和Ref是const T*和const T&

因此在我们的迭代器代码中,也应该定义这四种类型,因为我们这里只需要pointer和reference,所以这里我们只定义这两种,如下图一所示。那么这样reverse_iterator里面的operator*和operator->函数返回值就可以写成Iterator::reference和Iterator::pointer,如下图二所示。但是返回值如果直接写成Iterator::reference和Iterator::pointer是有问题的,编译器会报错不认识Iterator::reference和Iterator::pointer,这是因为Iterator是一个类模板,Iterator类模板还没有实例化,编译器不能去还没有实例化的模板中找东西(如果编译器允许去还没有实例化的模板中找东西,那么这里的Iterator::reference和Iterator::pointer会被翻译成T&和T*,当Iterator类模板实例化了之后只会修改Iterator类模板里面的T类型,不会去修改reverse_iterator类里面的T类型)。

   

类模板没有实例化之前不能去他里面找内嵌定义的类型(例如上面的pointer和reference),类模板没有实例化,找出来也是虚拟类型,后期无法处理。

这里我们要在Iterator::reference和Iterator::pointer的前面加上typename关键字,如下图所示,typename关键字我们之前讲模板的时候提过(模板参数定义的时候可以用class也可以用typename),这里我们使用typename关键字,其功能是告诉编译器typename关键字后面的这一串(Iterator::reference和Iterator::pointer)是一个类型,等Iterator实例化以后,再去他里面找这个内嵌类型。

官方库中反向迭代器的源代码在这个基础上还会再优化一下,如下图一所示,在reverse_iterator类模板中将Iterator::reference和Iterator::pointer类型重定义成reference和pointer,这里也需要加typename关键字,理由和上面相同。那么operator*和operator->前面可以直接用reference和pointer,如下图二所示

  

这样对于list类,我们就完成了像源代码一样的只有一个模板参数的reverse_iterator类模板。

4.上面注意点三的实现只有一个模板参数的reverse_iterator类模板思路对于string和vector容器是不行的,只有容器的迭代器是自定义类型的才能在里面类型重定义reference和pointer,然后在reverse_iterator类里面取迭代器类里面的内嵌类型reference和pointer,而string和vector容器的迭代器就是指针类型不是自定义类型的。

string和vector容器的解决方式有两种:

(1)不再使用原生指针作为string和vector容器的迭代器,去写一个__string_iterator和__vector_iterator的迭代器类,类里面去封装T*指针,然后在迭代器类里面实现operator++等操作,并且和list一样在类里面类型重定义reference和pointer即可

(2)萃取(源代码中的reverse_iterator类里面,对于自定义类型的迭代器会像list那样处理,对于像string和vector这样内置类型的迭代器,会进行迭代器萃取,迭代器的萃取下一节模板进阶我们会进行讲解)

5.如下图一所示的print_list和print_container代码是有问题的,因为在print_list模板函数中,list<T>这个类模板还没有实例化,因此不能去取里面的const_iterator内嵌类型,print_container模板函数中,Container还没有实例化,因此不能去取里面的const_iterator内嵌类型。需要在list<T>::const_iterator和Container::const_iterator的前面加上关键词typename才可以,如下图二所示。

注意:如果这里的list<T>::const_iterator和Container::const_iterator使用auto代替,那么auto前面是不用加typename的,因为auto会根据lt.begin()的返回值类型直接推出来。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本版本与网上其他资源不同之处在于,此版本可进行编辑,搜索,已进行内容识别扫描。可全选,可编辑,可剪切文字。 部分目录如下: 目录 第一篇预备知识 第1 章C++ 编程技术...................................................... 3 1-1 C++与C 语言的区别................................................... 4 1-1-1 文件扩展名的改变,.............................................. 4 1-1-2 简化输入/输出手段.............................................. 5 1-1-3 数据型声明的改变,............................................ 5 1-1-4 动态内存分配运算符的使用....................................... 6 1-1-5 弓I 用(References) 型, ··················•················•"'''8 1-1-6 const 语义的扩展................................................ 9 1-1-7 指针声明型与对象型相一致.................................. 13 1-1-8 int 与char 不再等价............................................. 13 1-1-9 结构数据型的变化............................................ 13 1-1-10 数组和指针技术的不同......................................... 14 1-2 C++存储技术........................................................ 15 1-2 一I C++存储型.................................................. 15 I6I7 ..... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. •. .• •. .• .. .. .. .. .. .. .. .. .. .. .. .. . 期 符存 饰生 修的 取象 存对 廿廿 I2I32 ~3 c c 1-3 C++ 函数技术........................................................ 19 1-3-1 的构造函数、析构函数与赋值函数,..... - ........ - .............. 19 1-3-2 在派生中实现的基本函数,................... _ ............... 29 1-3-3 内联函数技术,........ ................................... 30 3133 ..... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . 现 实 术的 技制 数机 函象 元对 友向 由 曰1. l -C 1 4 3337 ..... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . 术术 技技 承载 继重 的数 函 l4l44 3 ~ 3840 ..... .. .. .. .. .. .. •. .• .. .. .. .. .. .. .. .. .. .. .. •. .• .. •. .• •. •• .• .. .. .. .. .. .. .. .. .. •. •• .• . 术 技 术象 技抽 载和 重数 符函 算虚 运纯 l4l34 4 1-5 小结...............................................
The C++ Standard Library A Tutorial and Reference (2nd Edition)+cppstdlib-code.zip C++标准库(第二版)英文版.pdf 非扫描版+源代码 Prefaceto the SecondEdition xxiii Acknowledgments for the SecondEdition xxiv Prefaceto the FirstEdition xxv Acknowledgments for the FirstEdition xxvi 1 About This Book 1 1.1 Why This Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Before ReadingThis Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Styleand Structure of the Book . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.4 How to ReadThis Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.5 Stateof the Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.6 Example Codeand AdditionalInformation . . . . . . . . . . . . . . . . . . . . . 5 1.7 Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2 Introduction to C++ and the StandardLibrary 7 2.1 Historyof the C++ Standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.1 Common Questionsabout the C++11 Standard . . . . . . . . . . . . . . 8 2.1.2 Compatibility between C++98 and C++11 . . . . . . . . . . . . . . . . . 9 2.2 Complexity and Big-O Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3 New LanguageFeatures 13 3.1 New C++11 Language Features . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.1.1 Important MinorSyntax Cleanups . . . . . . . . . . . . . . . . . . . . . 13 3.1.2 AutomaticType Deductionwith auto . . . . . . . . . . . . . . . . . . . 14 3.1.3 UniformInitialization and Initializer Lists . . . . . . . . . . . . . . . . . 15 3.1.4 Range-Basedfor Loops . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.5 MoveSemanticsand Rvalue References . . . . . . . . . . . . . . . . . . 19 viii Contents 3.1.6 New String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.1.7 Keyword noexcept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.1.8 Keyword constexpr . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.1.9 New Template Features . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.1.10 Lambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.1.11 Keyword decltype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.1.12 New Function Declaration Syntax . . . . . . . . . . . . . . . . . . . . . 32 3.1.13 Scoped Enumerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.1.14 New FundamentalData Types . . . . . . . . . . . . . . . . . . . . . . . 33 3.2 Old “New” Language Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.2.1 ExplicitInitialization for FundamentalTypes . . . . . . . . . . . . . . . 37 3.2.2 Definitionof main() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 4 GeneralConcepts 39 4.1 Namespace std . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.2 Header Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4.3 Errorand ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3.1 Standard ExceptionClasses. . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3.2 Members of ExceptionClasses. . . . . . . . . . . . . . . . . . . . . . . 44 4.3.3 PassingExceptions with Classexception_ptr . . . . . . . . . . . . . . 52 4.3.4 Throwing Standard Exceptions . . . . . . . . . . . . . . . . . . . . . . . 53 4.3.5 Deriving from Standard ExceptionClasses. . . . . . . . . . . . . . . . . 54 4.4 CallableObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 4.5 Concurrencyand Multithreading. . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.6 Allocators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5 Utilities 59 5.1 Pairs and Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.1.1 Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.1.2 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 5.1.3 I/O for Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 5.1.4 Conversions between tuple sandpairs . . . . . . . . . . . . . . . . . . 75 5.2 Smart Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.2.1 Classshared_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.2.2 Classweak_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 5.2.3 Misusing Shared Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . 89 5.2.4 Shared and WeakPointersin Detail. . . . . . . . . . . . . . . . . . . . . 92 5.2.5 Classunique_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Contents ix 5.2.6 Classunique_ptrin Detail . . . . . . . . . . . . . . . . . . . . . . . . 110 5.2.7 Classauto_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 5.2.8 FinalWordsonSmart Pointers . . . . . . . . . . . . . . . . . . . . . . . 114 5.3 Numeric Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 5.4 Type Traitsand Type Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 5.4.1 Purposeof Type Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 5.4.2 Type Traitsin Detail. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 5.4.3 ReferenceWrappers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 5.4.4 Function Type Wrappers . . . . . . . . . . . . . . . . . . . . . . . . . . 133 5.5 Auxiliary Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 5.5.1 Processing the Minimumand Maximum. . . . . . . . . . . . . . . . . . 134 5.5.2 Swapping Two Va l u e s . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 5.5.3 SupplementaryComparison Operators . . . . . . . . . . . . . . . . . . . 138 5.6 Compile-Time FractionalArithmeticwith Classratio . . . . . . . . . . . . . 140 5.7 Clocks and Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 5.7.1 Overview of the ChronoLibrary . . . . . . . . . . . . . . . . . . . . . . 143 5.7.2 Durations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 5.7.3 Clocks and Timepoints . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 5.7.4 Date and TimeFunctions byC and POSIX . . . . . . . . . . . . . . . . . 157 5.7.5 Blocking with Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 5.8 Header Files , ,and . . . . . . . . . . . . . . 161 5.8.1 Definitionsin . . . . . . . . . . . . . . . . . . . . . . . . . . 161 5.8.2 Definitionsin . . . . . . . . . . . . . . . . . . . . . . . . . . 162 5.8.3 Definitionsin . . . . . . . . . . . . . . . . . . . . . . . . . . 163 6 The StandardTe m p l a t e Library 165 6.1 STL Components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 6.2 Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 6.2.1 Sequence Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 6.2.2 Associative Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 6.2.3 UnorderedContainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 6.2.4 Associative Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 6.2.5 OtherContainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 6.2.6 Container Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 6.3 Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 6.3.1 Further Examples of UsingAssociative and UnorderedContainers . . . . 193 6.3.2 Iterator Categories. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 x Contents 6.4 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 6.4.1 Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 6.4.2 Handling MultipleRanges . . . . . . . . . . . . . . . . . . . . . . . . . 207 6.5 Iterator Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 6.5.1 Insert Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 6.5.2 Stream Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 6.5.3 ReverseIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 6.5.4 MoveIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 6.6 User-DefinedGenericFunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 6.7 ManipulatingAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 6.7.1 “Removing”Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 6.7.2 ManipulatingAssociative and UnorderedContainers . . . . . . . . . . . 221 6.7.3 Algorithms versus MemberFunctions . . . . . . . . . . . . . . . . . . . 223 6.8 Functions as AlgorithmArguments . . . . . . . . . . . . . . . . . . . . . . . . . 224 6.8.1 UsingFunctions as AlgorithmArguments . . . . . . . . . . . . . . . . . 224 6.8.2 Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 6.9 UsingLambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 6.10 Function Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 6.10.1 Definitionof Function Objects . . . . . . . . . . . . . . . . . . . . . . . 233 6.10.2 PredefinedFunction Objects . . . . . . . . . . . . . . . . . . . . . . . . 239 6.10.3 Binders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 6.10.4 Function Objectsand Bindersversus Lambdas . . . . . . . . . . . . . . . 243 6.11 Container Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 6.11.1 Requirements for Container Elements . . . . . . . . . . . . . . . . . . . 244 6.11.2 Va l u eSemanticsor ReferenceSemantics. . . . . . . . . . . . . . . . . . 245 6.12 Errors and Exceptions inside the STL . . . . . . . . . . . . . . . . . . . . . . . . 245 6.12.1 ErrorHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 6.12.2 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 6.13 Extendingthe STL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 6.13.1 Integrating AdditionalTypes . . . . . . . . . . . . . . . . . . . . . . . . 250 6.13.2 Deriving from STL Types . . . . . . . . . . . . . . . . . . . . . . . . . . 251 7 STL Containers 253 7.1 Common Container Abilitiesand Operations . . . . . . . . . . . . . . . . . . . . 254 7.1.1 Container Abilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 7.1.2 Container Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 7.1.3 Container Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Contents xi 7.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 7.2.1 Abilitiesof Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 7.2.2 ArrayOperations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 7.2.3 Usingarray s as C-StyleArrays . . . . . . . . . . . . . . . . . . . . . . 267 7.2.4 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.2.5 TupleInterface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.2.6 Examples of UsingArrays . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.3 Ve c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 7.3.1 Abilitiesof Ve c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 7.3.2 Ve c t o r Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 7.3.3 UsingVe c t o r sas C-StyleArrays . . . . . . . . . . . . . . . . . . . . . . 278 7.3.4 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 7.3.5 Examples of UsingVe c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . 279 7.3.6 Classvector . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 7.4 Deques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 7.4.1 Abilitiesof Deques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 7.4.2 Deque Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 7.4.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 7.4.4 Examples of UsingDeques. . . . . . . . . . . . . . . . . . . . . . . . . 288 7.5 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 7.5.1 Abilitiesof Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 7.5.2 List Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 7.5.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 7.5.4 Examples of UsingLists . . . . . . . . . . . . . . . . . . . . . . . . . . 298 7.6 Forward Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 7.6.1 Abilitiesof Forward Lists . . . . . . . . . . . . . . . . . . . . . . . . . . 300 7.6.2 Forward List Operations . . . . . . . . . . . . . . . . . . . . . . . . . . 302 7.6.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 7.6.4 Examples of UsingForward Lists . . . . . . . . . . . . . . . . . . . . . . 312 7.7 Sets and Multisets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 7.7.1 Abilitiesof Sets and Multisets . . . . . . . . . . . . . . . . . . . . . . . 315 7.7.2 Setand MultisetOperations. . . . . . . . . . . . . . . . . . . . . . . . . 316 7.7.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 7.7.4 Examples of UsingSets and Multisets . . . . . . . . . . . . . . . . . . . 325 7.7.5 Example of Specifying the Sorting Criterion at Runtime . . . . . . . . . . 328 xii Contents 7.8 Mapsand Multimaps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 7.8.1 Abilitiesof Mapsand Multimaps. . . . . . . . . . . . . . . . . . . . . . 332 7.8.2 Map and Multimap Operations . . . . . . . . . . . . . . . . . . . . . . . 333 7.8.3 UsingMapsas Associative Arrays . . . . . . . . . . . . . . . . . . . . . 343 7.8.4 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 7.8.5 Examples of UsingMapsand Multimaps. . . . . . . . . . . . . . . . . . 345 7.8.6 Example with Maps,Strings,and Sorting Criterion at Runtime . . . . . . 351 7.9 UnorderedContainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 7.9.1 Abilitiesof UnorderedContainers . . . . . . . . . . . . . . . . . . . . . 357 7.9.2 Creating and Controlling UnorderedContainers . . . . . . . . . . . . . . 359 7.9.3 OtherOperationsfor UnorderedContainers . . . . . . . . . . . . . . . . 367 7.9.4 The Bucket Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 7.9.5 UsingUnorderedMapsas Associative Arrays . . . . . . . . . . . . . . . 374 7.9.6 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 7.9.7 Examples of UsingUnorderedContainers . . . . . . . . . . . . . . . . . 375 7.10 OtherSTL Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 7.10.1 Strings as STL Containers . . . . . . . . . . . . . . . . . . . . . . . . . 385 7.10.2 Ordinary C-StyleArrays as STL Containers . . . . . . . . . . . . . . . . 386 7.11 Implementing ReferenceSemantics . . . . . . . . . . . . . . . . . . . . . . . . . 388 7.12 Whento Use WhichContainer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 8 STL ContainerMembersin Detail 397 8.1 Type Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 8.2 Create, Copy,and DestroyOperations . . . . . . . . . . . . . . . . . . . . . . . . 400 8.3 Nonmodifying Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 8.3.1 Size Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 8.3.2 Comparison Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 8.3.3 Nonmodifying Operationsfor Associative and UnorderedContainers . . . 404 8.4 Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 8.5 Direct ElementAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 8.6 Operationsto Generate Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 8.7 Inserting and RemovingElements . . . . . . . . . . . . . . . . . . . . . . . . . . 411 8.7.1 Inserting Single Elements . . . . . . . . . . . . . . . . . . . . . . . . . . 411 8.7.2 Inserting MultipleElements . . . . . . . . . . . . . . . . . . . . . . . . . 416 8.7.3 RemovingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 8.7.4 Resizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 Contents xiii 8.8 Special MemberFunctions for Lists and Forward Lists . . . . . . . . . . . . . . . 420 8.8.1 Special MemberFunctions for Lists (and Forward Lists) . . . . . . . . . 420 8.8.2 Special MemberFunctions for Forward Lists Only . . . . . . . . . . . . 423 8.9 Container Policy Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 8.9.1 Nonmodifying Policy Functions . . . . . . . . . . . . . . . . . . . . . . 427 8.9.2 ModifyingPolicy Functions . . . . . . . . . . . . . . . . . . . . . . . . 428 8.9.3 Bucket Interface for UnorderedContainers . . . . . . . . . . . . . . . . . 429 8.10 Allocator Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430 8.10.1 FundamentalAllocator Members . . . . . . . . . . . . . . . . . . . . . . 430 8.10.2 Constructorswith Optional Allocator Parameters . . . . . . . . . . . . . 430 9 STL Iterators 433 9.1 Header Files for Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 9.2 Iterator Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 9.2.1 Output Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 9.2.2 Input Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 9.2.3 Forward Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 9.2.4 BidirectionalIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437 9.2.5 Random-Access Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . 438 9.2.6 The Incrementand DecrementProblem of Ve c t o r Iterators . . . . . . . . 440 9.3 Auxiliary Iterator Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 9.3.1 advance() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 9.3.2 next()and prev(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 9.3.3 distance() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 9.3.4 iter_swap() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 9.4 Iterator Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 9.4.1 ReverseIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 9.4.2 Insert Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 9.4.3 Stream Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 9.4.4 MoveIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 9.5 Iterator Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 9.5.1 WritingGenericFunctions for Iterators . . . . . . . . . . . . . . . . . . . 468 9.6 WritingUser-DefinedIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 xiv Contents 10 STL Function Objectsand UsingLambdas 475 10.1 The Conceptof Function Objects . . . . . . . . . . . . . . . . . . . . . . . . . . 475 10.1.1 Function Objectsas Sorting Criteria . . . . . . . . . . . . . . . . . . . . 476 10.1.2 Function Objectswith Internal State . . . . . . . . . . . . . . . . . . . . 478 10.1.3 The Return Va l u eof for_each() . . . . . . . . . . . . . . . . . . . . . 482 10.1.4 Predicatesversus Function Objects. . . . . . . . . . . . . . . . . . . . . 483 10.2 PredefinedFunction Objectsand Binders . . . . . . . . . . . . . . . . . . . . . . 486 10.2.1 PredefinedFunction Objects . . . . . . . . . . . . . . . . . . . . . . . . 486 10.2.2 Function Adapters and Binders. . . . . . . . . . . . . . . . . . . . . . . 487 10.2.3 User-DefinedFunction Objectsfor Function Adapters . . . . . . . . . . . 495 10.2.4 Deprecated Function Adapters . . . . . . . . . . . . . . . . . . . . . . . 497 10.3 UsingLambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499 10.3.1 Lambdas versus Binders . . . . . . . . . . . . . . . . . . . . . . . . . . 499 10.3.2 Lambdas versus StatefulFunction Objects. . . . . . . . . . . . . . . . . 500 10.3.3 Lambdas Calling Global and MemberFunctions . . . . . . . . . . . . . . 502 10.3.4 Lambdas as HashFunction, Sorting,or Equivalence Criterion . . . . . . . 504 11 STL Algorithms 505 11.1 AlgorithmHeader Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 11.2 AlgorithmOverview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 11.2.1 A BriefIntroduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 11.2.2 Classification of Algorithms . . . . . . . . . . . . . . . . . . . . . . . . 506 11.3 Auxiliary Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 11.4 The for_each()Algorithm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 11.5 Nonmodifying Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 11.5.1 Counting Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 11.5.2 Minimumand Maximum. . . . . . . . . . . . . . . . . . . . . . . . . . 525 11.5.3 SearchingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 11.5.4 Comparing Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 11.5.5 Predicatesfor Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550 11.6 ModifyingAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 11.6.1 Copying Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 11.6.2 MovingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 11.6.3 Transforming and Combining Elements . . . . . . . . . . . . . . . . . . 563 11.6.4 Swapping Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 11.6.5 AssigningNew Va l u e s . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 11.6.6 ReplacingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571 Contents xv 11.7 RemovingAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575 11.7.1 RemovingCertain Va l u e s . . . . . . . . . . . . . . . . . . . . . . . . . . 575 11.7.2 RemovingDuplicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578 11.8 Mutating Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 11.8.1 Reversingthe Orderof Elements . . . . . . . . . . . . . . . . . . . . . . 583 11.8.2 Rotating Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 11.8.3 PermutingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 11.8.4 Shuffling Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589 11.8.5 MovingElements to the Front . . . . . . . . . . . . . . . . . . . . . . . 592 11.8.6 Partition into Two Subranges . . . . . . . . . . . . . . . . . . . . . . . . 594 11.9 Sorting Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 11.9.1 Sorting AllElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 11.9.2 Partial Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599 11.9.3 Sorting Accordingto the n th Element . . . . . . . . . . . . . . . . . . . 602 11.9.4 HeapAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604 11.10 Sorted-Range Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.10.1SearchingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.10.2MergingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 11.11 Numeric Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623 11.11.1Processing Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623 11.11.2Converting Relativeand Absolute Va l u e s . . . . . . . . . . . . . . . . . . 627 12 SpecialContainers 631 12.1 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632 12.1.1 The Core Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633 12.1.2 Example of UsingStacks . . . . . . . . . . . . . . . . . . . . . . . . . . 633 12.1.3 A User-DefinedStackClass. . . . . . . . . . . . . . . . . . . . . . . . . 635 12.1.4 Classstack in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . 637 12.2 Queues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638 12.2.1 The Core Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 12.2.2 Example of UsingQueues . . . . . . . . . . . . . . . . . . . . . . . . . 640 12.2.3 A User-DefinedQueue Class . . . . . . . . . . . . . . . . . . . . . . . . 641 12.2.4 Classqueue in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . 641 12.3 PriorityQueues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641 12.3.1 The Core Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643 12.3.2 Example of UsingPriorityQueues. . . . . . . . . . . . . . . . . . . . . 643 12.3.3 Classpriority_queue in Detail . . . . . . . . . . . . . . . . . . . . 644 xvi Contents 12.4 Container Adapters in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645 12.4.1 Type Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645 12.4.2 Constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646 12.4.3 SupplementaryConstructorsfor PriorityQueues. . . . . . . . . . . . . . 646 12.4.4 Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647 12.5 Bitsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650 12.5.1 Examples of UsingBitsets . . . . . . . . . . . . . . . . . . . . . . . . . 651 12.5.2 Classbitsetin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . 653 13 Strings 655 13.1 Purposeof the String Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656 13.1.1 A First Example: Extractinga Temporary Filename . . . . . . . . . . . . 656 13.1.2 A Second Example: ExtractingWordsand PrintingThemBackward . . . 660 13.2 Description of the String Classes . . . . . . . . . . . . . . . . . . . . . . . . . . 663 13.2.1 String Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663 13.2.2 OperationOverview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666 13.2.3 Constructorsand Destructor . . . . . . . . . . . . . . . . . . . . . . . . 667 13.2.4 Strings and C-Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668 13.2.5 Size and Capacity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669 13.2.6 ElementAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671 13.2.7 Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672 13.2.8 Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 13.2.9 Substringsand String Concatenation . . . . . . . . . . . . . . . . . . . . 676 13.2.10Input/Output Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 677 13.2.11Searchingand Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 13.2.12The Va l u enpos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 13.2.13Numeric Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 13.2.14Iterator Supportfor Strings . . . . . . . . . . . . . . . . . . . . . . . . . 684 13.2.15Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689 13.2.16Performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 13.2.17Strings and Ve c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 13.3 String Classin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693 13.3.1 Type Definitionsand StaticVa l u e s . . . . . . . . . . . . . . . . . . . . . 693 13.3.2 Create, Copy,and DestroyOperations . . . . . . . . . . . . . . . . . . . 694 13.3.3 Operationsfor Size and Capacity . . . . . . . . . . . . . . . . . . . . . . 696 13.3.4 Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697 13.3.5 Character Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699 13.3.6 GeneratingC-Strings and Character Arrays . . . . . . . . . . . . . . . . 700 Contents xvii 13.3.7 ModifyingOperations. . . . . . . . . . . . . . . . . . . . . . . . . . . . 700 13.3.8 Searchingand Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . 708 13.3.9 Substringsand String Concatenation . . . . . . . . . . . . . . . . . . . . 711 13.3.10Input/Output Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 712 13.3.11Numeric Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713 13.3.12GeneratingIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714 13.3.13Allocator Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715 14 RegularExpressions 717 14.1 The Regex Matchand Search Interface . . . . . . . . . . . . . . . . . . . . . . . 717 14.2 Dealingwith Subexpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720 14.3 Regex Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726 14.4 Regex Token Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 14.5 ReplacingRegularExpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . 730 14.6 Regex Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732 14.7 Regex Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 14.8 The Regex ECMAScriptGrammar . . . . . . . . . . . . . . . . . . . . . . . . . 738 14.9 OtherGrammars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739 14.10 BasicRegex Signaturesin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . 740 15 Input/Output UsingStreamClasses 743 15.1 Common Background of I/O Streams . . . . . . . . . . . . . . . . . . . . . . . . 744 15.1.1 Stream Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 15.1.2 Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 15.1.3 Global Stream Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 15.1.4 Stream Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 15.1.5 Manipulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 15.1.6 A Simple Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 15.2 FundamentalStream Classesand Objects. . . . . . . . . . . . . . . . . . . . . . 748 15.2.1 Classes and ClassHierarchy . . . . . . . . . . . . . . . . . . . . . . . . 748 15.2.2 Global Stream Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 751 15.2.3 Header Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752 15.3 Standard Stream Operators <> . . . . . . . . . . . . . . . . . . . . . . . . 753 15.3.1 Output Operator <> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754 15.3.3 Input/Output of Special Types . . . . . . . . . . . . . . . . . . . . . . . 755 xviii Contents 15.4 Stateof Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758 15.4.1 Constants for the Stateof Streams . . . . . . . . . . . . . . . . . . . . . 758 15.4.2 MemberFunctions Accessingthe Stateof Streams. . . . . . . . . . . . . 759 15.4.3 Stream Stateand BooleanConditions . . . . . . . . . . . . . . . . . . . 760 15.4.4 Stream Stateand Exceptions . . . . . . . . . . . . . . . . . . . . . . . . 762 15.5 Standard Input/Output Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 767 15.5.1 MemberFunctions for Input . . . . . . . . . . . . . . . . . . . . . . . . 768 15.5.2 MemberFunctions for Output . . . . . . . . . . . . . . . . . . . . . . . 771 15.5.3 Example Uses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772 15.5.4 sentryObjects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772 15.6 Manipulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774 15.6.1 Overview of AllManipulators . . . . . . . . . . . . . . . . . . . . . . . 774 15.6.2 How ManipulatorsWork . . . . . . . . . . . . . . . . . . . . . . . . . . 776 15.6.3 User-DefinedManipulators. . . . . . . . . . . . . . . . . . . . . . . . . 777 15.7 Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779 15.7.1 Format Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779 15.7.2 Input/Output Format of BooleanVa l u e s . . . . . . . . . . . . . . . . . . 781 15.7.3 FieldWidth, Fill Character,and Adjustment . . . . . . . . . . . . . . . . 781 15.7.4 PositiveSign and UppercaseLetters . . . . . . . . . . . . . . . . . . . . 784 15.7.5 Numeric Base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 785 15.7.6 Floating-Point Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 15.7.7 GeneralFormatting Definitions . . . . . . . . . . . . . . . . . . . . . . . 789 15.8 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 790 15.9 File Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 15.9.1 File Stream Classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 15.9.2 Rvalue and MoveSemanticsfor File Streams . . . . . . . . . . . . . . . 795 15.9.3 File Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796 15.9.4 RandomAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 799 15.9.5 UsingFile Descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . 801 15.10 Stream Classesfor Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 15.10.1String Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 15.10.2MoveSemanticsfor String Streams. . . . . . . . . . . . . . . . . . . . . 806 15.10.3char* Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807 15.11 Input/Output Operators for User-DefinedTypes . . . . . . . . . . . . . . . . . . . 810 15.11.1Implementing Output Operators . . . . . . . . . . . . . . . . . . . . . . 810 15.11.2Implementing Input Operators . . . . . . . . . . . . . . . . . . . . . . . 812 15.11.3Input/Output UsingAuxiliary Functions . . . . . . . . . . . . . . . . . . 814 Contents xix 15.11.4User-DefinedFormat Flags . . . . . . . . . . . . . . . . . . . . . . . . . 815 15.11.5Conventionsfor User-DefinedInput/Output Operators . . . . . . . . . . . 818 15.12 Connecting Input and Output Streams . . . . . . . . . . . . . . . . . . . . . . . . 819 15.12.1Loose Coupling Usingtie() . . . . . . . . . . . . . . . . . . . . . . . . 819 15.12.2TightCoupling UsingStream Buffers . . . . . . . . . . . . . . . . . . . 820 15.12.3Redirecting Standard Streams. . . . . . . . . . . . . . . . . . . . . . . . 822 15.12.4Streamsfor Readingand Writing. . . . . . . . . . . . . . . . . . . . . . 824 15.13 The Stream Buffer Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826 15.13.1The Stream Buffer Interfaces . . . . . . . . . . . . . . . . . . . . . . . . 826 15.13.2Stream Buffer Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . 828 15.13.3User-DefinedStream Buffers . . . . . . . . . . . . . . . . . . . . . . . . 832 15.14 PerformanceIssues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844 15.14.1Synchronization with C’sStandard Streams . . . . . . . . . . . . . . . . 845 15.14.2Buffering in Stream Buffers . . . . . . . . . . . . . . . . . . . . . . . . . 845 15.14.3UsingStream Buffers Directly . . . . . . . . . . . . . . . . . . . . . . . 846 16 Internationalization 849 16.1 Character Encodingsand Character Sets . . . . . . . . . . . . . . . . . . . . . . . 850 16.1.1 Multibyte and Wide-CharacterText . . . . . . . . . . . . . . . . . . . . . 850 16.1.2 Different Character Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . 851 16.1.3 Dealingwith Character Sets in C++ . . . . . . . . . . . . . . . . . . . . 852 16.1.4 Character Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853 16.1.5 Internationalization of Special Characters . . . . . . . . . . . . . . . . . 857 16.2 The Conceptof Locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 857 16.2.1 UsingLocales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858 16.2.2 Locale Facets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864 16.3 Localesin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866 16.4 Facets in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869 16.4.1 Numeric Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 870 16.4.2 Monetary Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 16.4.3 Timeand Date Formatting . . . . . . . . . . . . . . . . . . . . . . . . . 884 16.4.4 Character Classification and Conversion . . . . . . . . . . . . . . . . . . 891 16.4.5 String Collation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904 16.4.6 Internationalized Messages . . . . . . . . . . . . . . . . . . . . . . . . . 905 xx Contents 17 Numerics 907 17.1 RandomNumbers and Distributions. . . . . . . . . . . . . . . . . . . . . . . . . 907 17.1.1 A First Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908 17.1.2 Engines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912 17.1.3 Enginesin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915 17.1.4 Distributions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 17.1.5 Distributionsin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 17.2 Complex Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 17.2.1 Classcomplex in General . . . . . . . . . . . . . . . . . . . . . . . . 925 17.2.2 Examples UsingClasscomplex . . . . . . . . . . . . . . . . . . . . . 926 17.2.3 Operationsfor Complex Numbers . . . . . . . . . . . . . . . . . . . . . 928 17.2.4 Classcomplex in Detail . . . . . . . . . . . . . . . . . . . . . . . . . 935 17.3 Global Numeric Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941 17.4 Va l a r r a y s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943 18 Concurrency 945 18.1 The High-Level Interface: async() and Futures . . . . . . . . . . . . . . . . . . 946 18.1.1 A First Example Usingasync() and Futures . . . . . . . . . . . . . . . 946 18.1.2 AnExample of Waitingfor Two Tasks . . . . . . . . . . . . . . . . . . . 955 18.1.3 Shared Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 960 18.2 The Low-Level Interface: Threadsand Promises . . . . . . . . . . . . . . . . . . 964 18.2.1 Classstd::thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 964 18.2.2 Promises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969 18.2.3 Classpackaged_task . . . . . . . . . . . . . . . . . . . . . . . . . . 972 18.3 Startinga Thread in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973 18.3.1 async() in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 974 18.3.2 Futuresin Detail. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975 18.3.3 Shared Futuresin Detail. . . . . . . . . . . . . . . . . . . . . . . . . . . 976 18.3.4 Classstd::promise in Detail . . . . . . . . . . . . . . . . . . . . . . . 977 18.3.5 Classstd::packaged_task in Detail . . . . . . . . . . . . . . . . . . . 977 18.3.6 Classstd::thread in Detail . . . . . . . . . . . . . . . . . . . . . . . . 979 18.3.7 Namespace this_thread . . . . . . . . . . . . . . . . . . . . . . . . . 981 18.4 Synchronizing Threads, or the Problem of Concurrency . . . . . . . . . . . . . . 982 18.4.1 Bewareof Concurrency! . . . . . . . . . . . . . . . . . . . . . . . . . . 982 18.4.2 The Reason for the Problem of Concurrent Data Access . . . . . . . . . . 983 18.4.3 WhatExactlyCan GoWrong (the Extent of the Problem) . . . . . . . . . 983 18.4.4 The Features to Solvethe Problems . . . . . . . . . . . . . . . . . . . . . 987 Contents xxi 18.5 Mutexesand Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 989 18.5.1 UsingMutexesand Locks . . . . . . . . . . . . . . . . . . . . . . . . . . 989 18.5.2 Mutexesand Locks in Detail . . . . . . . . . . . . . . . . . . . . . . . . 998 18.5.3 Calling Oncefor MultipleThreads . . . . . . . . . . . . . . . . . . . . . 1000 18.6 ConditionVa r i a b l e s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 18.6.1 Purposeof ConditionVa r i a b l e s . . . . . . . . . . . . . . . . . . . . . . . 1003 18.6.2 A First Complete Example for ConditionVa r i a b l e s . . . . . . . . . . . . 1004 18.6.3 UsingConditionVa r i a b l e s to Implement a Queue for MultipleThreads . . 1006 18.6.4 ConditionVa r i a b l e s in Detail . . . . . . . . . . . . . . . . . . . . . . . . 1009 18.7 Atomics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1012 18.7.1 Example of UsingAtomics . . . . . . . . . . . . . . . . . . . . . . . . . 1012 18.7.2 Atomicsand TheirHigh-Level Interface in Detail . . . . . . . . . . . . . 1016 18.7.3 The C-StyleInterface of Atomics . . . . . . . . . . . . . . . . . . . . . . 1019 18.7.4 The Low-Level Interface of Atomics . . . . . . . . . . . . . . . . . . . . 1019 19 Allocators 1023 19.1 UsingAllocatorsas an Application Programmer . . . . . . . . . . . . . . . . . . 1023 19.2 A User-DefinedAllocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1024 19.3 UsingAllocatorsas a LibraryProgrammer . . . . . . . . . . . . . . . . . . . . . 1026 Bibliography 1031 Newsgroups and Forums . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1031 Books and Web Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 Index 1037 This page intentionally left blank
第一篇 预备知识 第1章 C++编程技术 2 1.1 和对象 2 1.2 的继承 5 1.3 函数重载 5 1.4 访问控制 7 1.5 操作符重载 8 1.6 显式型转换 9 1.7 异常处理 13 1.8 名字空间 17 1.9 友员函数 20 1.10 内联函数 21 1.11 静态成员 22 1.12 本章小结 23 第2章 C++模板技术 25 2.1 函数模板 25 2.2 模板 27 2.3 模板完全特化 28 2.4 函数模板重载 30 2.5 模板继承 30 2.6 本章小结 31 第3章 C++ I/O流技术 32 3.1 I/O流 32 3.2 标准输入输出 34 3.3 文件输入输出 36 3.4 流的格式控制 41 3.5 本章小结 45 第二篇 C++ STL泛化技术基础 第4章 C++ STL泛型库概述 48 4.1 C++ STL的发展历程 48 4.2 C++ STL的各种实现版本 49 4.2.1 HP STL 49 4.2.2 SGI STL 50 4.2.3 STLport 50 4.2.4 P.J.Plauger STL 50 4.2.5 Rouge Wave STL 50 4.3 C++ STL的Visual C++编译 50 4.4 C++ STL的体系结构 52 4.4.1 容器(Container) 52 4.4.2 迭代器(Iterator) 53 4.4.3 算法(Algorithm) 53 4.4.4 函数对象(Function Object) 54 4.4.5 适配器(Adapter) 55 4.4.6 内存分配器(Allocator) 56 4.4.7 概念(Concept)和模型(Model) 56 4.5 C++ STL存在的一些问题 57 4.6 本章小结 57 第5章 C++ STL泛化技术分析 58 5.1 算法和迭代器 58 5.1.1 算法 58 5.1.2 迭代器 61 5.1.3 函数对象 65 5.1.4 适配器 68 5.2 内存分配器和容器 74 5.2.1 内存分配器 75 5.2.2 容器 77 5.3 概念 82 5.3.1 基础性概念 82 5.3.2 容器概念 84 5.3.3 迭代器概念 86 5.3.4 函数对象概念 88 5.4 本章小结 89 第三篇 C++ STL容器技术 第6章 vector向量容器 92 6.1 vector技术原理 92 6.2 vector应用基础 94 6.3 本章小结 101 第7章 deque双端队列容器 102 7.1 deque技术原理 102 7.2 deque应用基础 108 7.3 本章小结 115 第8章 list双向链表容器 116 8.1 list技术原理 116 8.2 list应用基础 124 8.3 本章小结 131 第9章 slist单向链表容器 132 9.1 slist技术原理 132 9.2 slist应用基础 140 9.3 本章小结 148 第10章 bit_vector位向量容器 149 10.1 bit_vector技术原理 149 10.2 bit_vector应用基础 156 10.3 本章小结 161 第11章 set集合容器 162 11.1 set技术原理 162 11.2 set应用基础 181 11.3 本章小结 186 第12章 multiset多重集合容器 187 12.1 multiset技术原理 187 12.2 multiset应用基础 190 12.3 本章小结 196 第13章 map映照容器 197 13.1 map技术原理 197 13.2 map应用基础 200 13.3 本章小结 206 第14章 multimap多重映照容器 207 14.1 multimap技术原理 207 14.2 multimap应用基础 210 14.3 本章小结 216 第15章 hash_set哈希集合容器 217 15.1 hash_set技术原理 217 15.2 hash_set应用基础 230 15.3 本章小结 234 第16章 hash_map哈希映照容器 235 16.1 hash_map技术原理 235 16.2 hash_map应用基础 237 16.3 本章小结 242 第17章 string基本字符序列容器 243 17.1 string技术原理 243 17.2 string应用基础 258 17.3 本章小结 264 第18章 stack堆栈容器 265 18.1 stack技术原理 265 18.2 stack应用基础 266 18.3 本章小结 269 第19章 queue队列容器 270 19.1 queue技术原理 270 19.2 queue应用基础 271 19.3 本章小结 274 第20章 priority_queue优先队列容器 275 20.1 priority_queue技术原理 275 20.2 priority_queue应用基础 278 20.3 本章小结 281 第四篇 C++ STL算法技术 第21章 非变易算法 284 21.1 逐个容器元素for_each 284 21.2 查找容器元素find 285 21.3 条件查找容器元素find_if 286 21.4 邻近查找容器元素adjacent_find 287 21.5 范围查找容器元素find_first_of 289 21.6 统计等于某值的容器元素个数count 290 21.7 条件统计容器元素个数count_if 291 21.8 元素不匹配查找mismatch 293 21.9 元素相等判断equal 295 21.10 子序列搜索search 296 21.11 重复元素子序列搜索search_n 299 21.12 最后一个子序列搜索find_end 301 21.13 本章小结 303 第22章 变易算法 304 22.1 元素复制copy 304 22.2 反向复制copy_backward 305 22.3 元素交换swap 306 22.4 迭代器交换iter_swap 307 22.5 区间元素交换swap_ranges 308 22.6 元素变换transform 309 22.7 替换 310 22.8 条件替换replace_if 311 22.9 替换和复制replace_copy 312 22.10 条件替换和复制replace_copy_if 313 22.11 填充fill 314 22.12 n次填充fill_n 315 22.13 随机生成元素generate 316 22.14 随机生成n个元素generate_n 317 22.15 移除复制remove_copy 318 22.16 条件移除复制remove_copy_if 319 22.17 移除remove 320 22.18 条件移除remove_if 321 22.19 不连续重复元素复制unique_copy 322 22.20 剔除连续重复元素unique 324 22.21 元素反向reverse 325 22.22 反向复制reverse_copy 326 22.23 旋转rotate 327 22.24 旋转复制rotate_copy 329 22.25 随机抖动random_shuffle 330 22.26 随机采样random_sample 331 22.27 容器分割partition 333 22.28 容器稳定分割stable_partition 335 22.29 本章小结 338 第23章 排序算法 339 23.1 元素入堆push_heap 339 23.2 创建堆make_heap 343 23.3 元素出堆pop_heap 348 23.4 堆排序sort_heap 351 23.5 是否为堆is_heap 352 23.6 局部排序partial_sort 354 23.7 局部排序复制partial_sort_copy 356 23.8 排序sort 359 23.9 归并merge 366 23.10 内部归并inplace_merge 368 23.11 稳定排序stable_sort 376 23.12 是否排序is_sorted 383 23.13 第n个元素nth_element 384 23.14 下确界lower_bound 386 23.15 上确界upper_bound 388 23.16 等价区间equal_range 390 23.17 折半搜索binary_search 392 23.18 子集合includes 393 23.19 集合求并set_union 394 23.20 集合求交set_ intersection 396 23.21 集合求差set_difference 398 23.22 集合求异set_symmetric_difference 399 23.23 最小值min 401 23.24 最大值max 402 23.25 最小元素min_element 403 23.26 最大元素max_element 404 23.27 字典比较lexicographical_compare 405 23.28 下一排列组合next_permutation 406 23.29 上一排列组合prev_permutation 409 23.30 本章小结 411 第24章 数值算法 412 24.1 递增赋值iota 412 24.2 元素求和accumulate 413 24.3 两序列元素内积inner_product 414 24.4 部分元素求和partial_sum 415 24.5 相邻元素求差adjacent_difference 417 24.6 n次方计算power 419 24.7 本章小结 421 第五篇 C++ STL迭代器技术 第25章 输入输出流迭代器 424 25.1 输入流迭代器 424 25.2 输出流迭代器 426 25.3 本章小结 427 第26章 插入/反向/存储迭代器 428 26.1 向前插入迭代器 428 26.2 向后插入迭代器 429 26.3 插入迭代器 431 26.4 反向迭代器 432 26.5 反向双向迭代器 434 26.6 原始存储迭代器 435 26.7 本章小结 437 附录 STL版权说明 438

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随风张幔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值