7 STL

1、STL简介

1.1基本概念

可复用利用的东西!

面向对象和泛型编程(模板)的 目的->提升复用性

为了建立数据结构和算法的一套标准->STL横空出世

  • STL(Standard Template Liberary)标准模板库
  • 广义分:容器、算法、迭代器
  • 容器和算法之间通过迭代器连接、STL几乎所有的代码均采用函数模板和类模板

1.2六大组件

  • 容器:各种数据结构,如vector、list、deque、map、set等由于数据存储。

       序列式排序:强调值的排序,序列式容器中的每个元素均有固定的位置。

       关联式排序:二叉树结构,各元素之间没有严格的物理的顺序关系。

  • 算法:各种算法,如:sort、find、copy、for_each等。
  • 迭代器:容器和算法连接桥梁。

       提供一种方法,使之间能够依次序访问某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器。类似于指针,可简单理解为指针。

迭代器种类:

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

常用的容器中迭代器种类为双向迭代器,和随机访问迭代器

  • 仿函数:作为算法的某种策略。
  • 适配器(配接器):一种用来修饰容器或者仿函数或迭代接口的东西。
  • 空间配置器:负责空间的配置与管理。

1.3容器、算法、迭代器案例(Vector)

创建、插入、遍历

1.3.1vector存放内置数据类型

案例代码:

//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:
	void test_exp();
};

//.cpp
#include "STL_Vector.h"

using namespace std;
void func(int val)
{
	cout << val << endl;
}
void STL_Vector::test_exp()
{
	//创建
	vector  v;
	//添加
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);
	//遍历
	
	vector::iterator it_begin = v.begin();
	vector::iterator it_end = v.end();
	//方式一
	while (it_begin != it_end)
	{
		cout << *it_begin << endl;
		it_begin++;
	}

	//方式二

	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}

	//方式三
	for_each(v.begin(), v.end(), func);

}

//mian
#include "iostream"
using namespace std;
#include "STL_Vector.h"

int main()
{
	STL_Vector sv = STL_Vector();
	sv.test_exp();
	system("pause");
	return 0;
}

 运行结果:

1.3.2vector存放自定义数据类型及自定义对象指针

代码示例:

//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:
	void test_exp();
};

//.cpp

#include "STL_Vector.h"
using namespace std;

class Animal
{
public:
	Animal(int age,string name)
	{
		m_age = age;
		m_name = name;
	}
public:
	int m_age;
	string m_name;
};
void func(int val)
{
	cout << val;
}
void STL_Vector::test_exp()
{
	//创建
	vectorv_p;
	vectorv_point;
	//添加
	Animal a1(12,"僧面侯");
	Animal a2(12, "熊猫");
	Animal a3(12, "考拉");
	Animal a4(12, "袋鼠");
	v_p.push_back(a1);
	v_p.push_back(a2);
	v_p.push_back(a3);
	v_p.push_back(a3);

	v_point.push_back(&a1);
	v_point.push_back(&a2);
	v_point.push_back(&a3);
	v_point.push_back(&a4);

	//遍历

	for (vector::iterator it = v_p.begin(); it != v_p.end(); it++)
	{
		cout << "年龄:" << it->m_age << "姓名:" << (*it).m_name << endl;
	}
	for (vector::iterator it = v_point.begin(); it != v_point.end(); it++)
	{
		cout << "年龄:" << (*it)->m_age << "姓名:" << (*it)->m_name << endl;
	}

}

//main
#include "iostream"
using namespace std;
#include "STL_Vector.h"

int main()
{
	STL_Vector sv = STL_Vector();
	sv.test_exp();
	system("pause");
	return 0;
}

运行结果:

7 STL_第1张图片

1.3.3容器嵌套-有点二维数组的意思

代码示例:

//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:
	void test_exp();
};

//.cpp
#include "STL_Vector.h"
using namespace std;

class Animal
{
public:
	Animal(int age,string name)
	{
		m_age = age;
		m_name = name;
	}
public:
	int m_age;
	string m_name;
};
void func(int val)
{
	cout << val;
}
void STL_Vector::test_exp()
{
	//创建
	vector> v_nest;
	vector v_nest1;
	vector v_nest2;
	vector v_nest3;
	vector v_nest4;


	//添加
	for (int i = 0; i < 5; i++)
	{
		if (i % 2 == 0)
		{
			v_nest1.push_back("我里个豆");
			v_nest2.push_back("我里个豆");
			v_nest3.push_back("我里个豆");
			v_nest4.push_back("我里个豆");
		}
		else
		{
			v_nest1.push_back("我里个乖");
			v_nest2.push_back("我里个乖");
			v_nest3.push_back("我里个乖");
			v_nest4.push_back("我里个乖");
		}
		
	}
	v_nest.push_back(v_nest1);
	v_nest.push_back(v_nest2);
	v_nest.push_back(v_nest3);
	v_nest.push_back(v_nest4);

	//遍历
	for (vector>::iterator it = v_nest.begin(); it != v_nest.end(); it++)
	{
		for (vector::iterator itt = (*it).begin(); itt != (*it).end(); itt++)
		{
			cout << (*itt) ;
		}
		cout << endl;
	}
}
//mian
#include "iostream"
using namespace std;
#include "STL_Vector.h"

int main()
{
	STL_Vector sv = STL_Vector();
	sv.test_exp();
	system("pause");
	return 0;
}

7 STL_第2张图片

2、常用容器

2.1string

本质:string是C++风格的字符串,string是一个类。

char *是一个指针,是C风格的字符串

string是一个类,封装了char*,管理和维护char*的容器

2.1.1string构造函数

  • 无参构造string();构造语句  string str;
  • 字符串初始化string(const char * str);
  • 拷贝构造string(const string& str);
  • n个字符构造string(int n,char c);

代码示例:

//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:
	void test();

};

//.cpp
#include "string_.h"
#include "string"
void string_::test()
{
	//
	string str1;

	string str2 = "无语";

	string str3 = string(str2);

	string str4 = string(4, 'c');
	cout << "str1:" << str1 << endl;
	cout << "str2:" << str2 << endl;
	cout << "str3:" << str3 << endl;
	cout << "str4:" << str4 << endl;

}

int main()
{
	string_ t;
	t.test();
	system("pause");
	return 0;
}

运行结果:

 7 STL_第3张图片

2.1.2string的赋值操作

  • string& operator=(const char* s); //char*类型字符串 赋值给当前的字符串

  • string& operator=(const string &s); //把字符串s赋给当前的字符串

  • string& operator=(char c); //字符赋值给当前的字符串

  • string& assign(const char *s); //把字符串s赋给当前的字符串

  • string& assign(const char *s, int n); //把字符串s的前n个字符赋给当前的字符串

  • string& assign(const string &s); //把字符串s赋给当前字符串

  • string& assign(int n, char c); //用n个字符c赋给当前字符串

代码示例:

//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:
	void test01();

};


//.cpp
#include "string_.h"
#include "string"
using namespace std;
//string & operator=(const char* s); //char*类型字符串 赋值给当前的字符串
//
//string& operator=(const string& s); //把字符串s赋给当前的字符串
//
//string& operator=(char c); //字符赋值给当前的字符串
//
//string& assign(const char* s); //把字符串s赋给当前的字符串
//
//string& assign(const char* s, int n); //把字符串s的前n个字符赋给当前的字符串
//
//string& assign(const string& s); //把字符串s赋给当前字符串
//
//string& assign(int n, char c); //用n个字符c赋给当前字符串
void string_::test01()
{
	string str1 = "无语考拉";
	string str2 = str1;
	string str3;
	str3 = 'a';
	string str4;
	str4.assign("无语拉拉");
	string str5;
	str5.assign(str4);
	string str6;
	str6.assign(4, 'c');
	cout << "str1 = " << str1 << endl;
	cout << "str2 = " << str2 << endl;
	cout << "str3 = " << str3 << endl;
	cout << "str4 = " << str4 << endl;
	cout << "str5 = " << str5 << endl;
	cout << "str6 = " << str6 << endl;
}

int main()
{
	string_ t;
	t.test01();
	system("pause");
	return 0;
}

运行结果:

7 STL_第4张图片

 2.1.3string字符串拼接

  • string& operator+=(const char* str); //重载+=操作符

  • string& operator+=(const char c); //重载+=操作符

  • string& operator+=(const string& str); //重载+=操作符

  • string& append(const char *s); //把字符串s连接到当前字符串结尾

  • string& append(const char *s, int n); //把字符串s的前n个字符连接到当前字符串结尾

  • string& append(const string &s); //同operator+=(const string& str)

  • string& append(const string &s, int pos, int n);//字符串s中从pos开始的n个字符连接到字符串结尾

代码示例:


//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:
	void test02();

};



//.cpp
#include "string_.h"
#include "string"
using namespace std;
//*`string& operator+=(const char* str); `                   //重载+=操作符
//* `string& operator+=(const char c); `                         //重载+=操作符
//* `string& operator+=(const string& str); `                //重载+=操作符
//* `string& append(const char* s); `                               //把字符串s连接到当前字符串结尾
//* `string& append(const char* s, int n); `                 //把字符串s的前n个字符连接到当前字符串结尾
//* `string& append(const string& s); `                           //同operator+=(const string& str)
//* `string& append(const string& s, int pos, int n); `/ / 字符串s中从pos开始的n个字符连接到字符串结尾
void string_::test02()
{
	string str1 = "WC!";
	string str2;
	str2 += str1;
	string str3;
	str3 += str2;
	str3 += 'm';
	string str4;
	str4 += str2;
	str4 += "md";

	string str5;
	str5.append(str2);
	string str6;
	str6.append(str1, 2);
	str6.append(str2, 0, 2);

	cout << "str1 = " << str1 << endl;
	cout << "str2 = " << str2 << endl;
	cout << "str3 = " << str3 << endl;
	cout << "str4 = " << str4 << endl;
	cout << "str5 = " << str5 << endl;
	cout << "str6 = " << str6 << endl;

}

int main()
{
	string_ t;
	t.test02();
	system("pause");
	return 0;
}

运行结果:

2.1.4string查找和替换

  • int find(const string& str, int pos = 0) const; //查找str第一次出现位置,从pos开始查找

  • int find(const char* s, int pos = 0) const; //查找s第一次出现位置,从pos开始查找

  • int find(const char* s, int pos, int n) const; //从pos位置查找s的前n个字符第一次位置

  • int find(const char c, int pos = 0) const; //查找字符c第一次出现位置

  • int rfind(const string& str, int pos = npos) const; //查找str最后一次位置,从pos开始查找

  • int rfind(const char* s, int pos = npos) const; //查找s最后一次出现位置,从pos开始查找

  • int rfind(const char* s, int pos, int n) const; //从pos查找s的前n个字符最后一次位置

  • int rfind(const char c, int pos = 0) const; //查找字符c最后一次出现位置

  • string& replace(int pos, int n, const string& str); //替换从pos开始n个字符为字符串str

  • string& replace(int pos, int n,const char* s); //替换从pos开始的n个字符为字符串s

总结:

  • find查找是从左往后,rfind从右往左

  • find找到字符串后返回查找的第一个字符位置,找不到返回-1

  • replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串(全换进去)

2.1.5string比较

  • 字符串比较是按字符的ASCII码进行对比

= 返回 0

> 返回 1

< 返回 -1

函数原型:

  • int compare(const string &s) const; //与字符串s比较

  • int compare(const char *s) const; //与字符串s比较

2.1.6string插入和删除

  • string& insert(int pos, const char* s); //插入字符串

  • string& insert(int pos, const string& str); //插入字符串

  • string& insert(int pos, int n, char c); //在指定位置插入n个字符c

  • string& erase(int pos, int n = npos); //删除从Pos开始的n个字符

插入和删除的起始坐标0开始!

2.1.7string截取子串

函数原型:

string substr(int pos = 0, int n = npos) const; //返回由pos开始的n个字符组成的字符串

代码示例:

void string_::test04()
{
	string str = "sefgsfsdfdsfg";
	string substr = str.substr(1, 5);
	cout << "substr:" << substr<

运行结果:

7 STL_第5张图片

2.1.8string字符中字符获取与修改

string中单个字符存取方式有两种

  • char& operator[](int n); //通过[]方式取字符

  • char& at(int n); //通过at方法获取字符

代码示例:

void string_::test03()
{
	string str = "卧槽了,我去!";
	str[2] = 'a';
	for (int i = 0; i < str.size(); i++)
	{
		cout << str[i] ;
	}
	cout << endl;
	str.at(2) = 'a';
	for (int i = 0; i < str.size(); i++)
	{
		cout << str.at(i);
	}
}

string字符串中单个字符存取有两种方式,利用 [ ] 或 at  

2.2vector容器 

2.2.1vector基本概念

又称单端数组

与数组的最大区别,数组静态的,vector可动态申请空间,采用的方式是动态扩展

即复制原数据到新开辟空间的上,并释放原空间

常用函数及迭代器:

7 STL_第6张图片

vector容器是支持随机访问的迭代器

 2.2.2vector构造函数

  • vector v; //采用模板实现类实现,默认构造函数

  • vector(v.begin(), v.end()); //将v[begin(), end())前闭后开区间中的元素拷贝给本身。

  • vector(n, elem); //构造函数将n个elem拷贝给本身。

  • vector(const vector &vec); //拷贝构造函数。

2.2.3vector赋值操作

  • vector& operator=(const vector &vec);//重载等号操作符

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

2.2.4vector容量

  • empty(); //判断容器是否为空,空返回为true,否则为false

  • capacity(); //容器的容量capacity >= size;

  • size(); //返回容器中元素的个数

  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置。

                                  //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

                                            //如果容器变短,则末尾超出容器长度的元素被删除

2.2.5 vector插入和删除

  • push_back(ele); //尾部插入元素ele

  • pop_back(); //删除最后一个元素

  • insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele

  • insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele

  • erase(const_iterator pos); //删除迭代器指向的元素

  • erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素

  • clear(); //删除容器中所有元素

2.2.6vector数据获取

  • at(int idx); //返回索引idx所指的数据

  • operator[]; //返回索引idx所指的数据

  • front(); //返回容器中第一个数据元素

  • back(); //返回容器中最后一个数据元素

注意:是迭代器参数!

2.2.7vector互换

功能描述:

  • 实现两个容器内元素进行互换

函数原型:

  • swap(vec); // 将vec与本身的元素互换

实际用途:收缩内存空间

v.swap(v);

v的申请空间很大,但实际用的很少,内存浪费!于是vector (v).swap(v);

vector (v)为匿名对象,其占用内存和v一样,但申请空间和占用空间一致,最后再换给v,使得空间压缩,不浪费了!

2.2.8vector预留空间

功能描述:

  • 减少vector在动态扩展容量时的扩展次数

函数原型:

  • reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。

2.3deque容器

2.3.1deque基本概念和原理

功能:

  • 双端数组,可以对头端进行插入删除操作

deque与vector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低

  • deque相对而言,对头部的插入删除速度回比vector快

  • vector访问元素时的速度会比deque快,这和两者内部实现有关

常用迭代器和函数:

7 STL_第7张图片

deque内部工作原理:

deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据

中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

deque容器的迭代器也是支持随机访问的。

7 STL_第8张图片

2.3.2deque构造函数

  • deque deqT; //默认构造形式

  • deque(beg, end); //构造函数将[beg, end)区间中的元素拷贝给本身。

  • deque(n, elem); //构造函数将n个elem拷贝给本身。

  • deque(const deque &deq); //拷贝构造函数

注意:

//参数是const只读模式,则迭代器也应该变为只读迭代器

void printDeque(const deque& d) 
{
    for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
        cout << *it << " ";

    }
    cout << endl;
}

2.3.4 deque赋值

  • deque& operator=(const deque &deq); //重载等号操作符

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

2.3.4deque大小获取、大小更改、判空

  • deque.empty(); //判断容器是否为空

  • deque.size(); //返回容器中元素的个数

  • deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

  • deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

注意:

deque没有capacity属性!

2.3.5deque插入与删除

  • push_back(elem); //在容器尾部添加一个数据

  • push_front(elem); //在容器头部插入一个数据

  • pop_back(); //删除容器最后一个数据

  • pop_front(); //删除容器第一个数据

指定位置操作:

pos是迭代器位置

  • insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。

  • insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。

  • insert(pos,v.beg,v.end); //在pos位置插入迭代器[beg,end)区间的数据,无返回值。

  • clear(); //清空容器的所有数据

  • erase(beg,end); //删除迭代器[beg,end)区间的数据,返回下一个数据的位置。

  • erase(pos); //删除pos位置的数据,返回下一个数据的位置。

2.3.6数据获取

  • at(int idx); //返回索引idx所指的数据

  • operator[]; //返回索引idx所指的数据

  • front(); //返回容器中第一个数据元素

  • back(); //返回容器中最后一个数据元素

2.3.7排序

  • sort(iterator beg, iterator end) //对beg和end区间内元素进行排序

注意:#include ”algorithm“;

2.4容器案例

有5名选手,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。

代码示例:

//.h
#pragma once
#include "vector"
#include "deque"
#include "string"
using namespace std;
class player
{
public:
	string m_name;
	deque m_scores;
};
class Exa_evaluate_score
{
public:
	Exa_evaluate_score();
	void eval(int index);
	void summarizing(int index);
public:

	vector m_p;
};

//.cpp
#include "Exa_evaluate_score.h"
#include "string"
#include "deque"
#include 
#include "algorithm"
using namespace std;


Exa_evaluate_score::Exa_evaluate_score()
{
	m_p.resize(10);
}
void Exa_evaluate_score::eval(int index)
{
	cout << "请输入第" << index+1 << "位选手得分:" << endl;
	cout << "输入姓名:" ;
	string name;
	getline(cin, name);
	m_p[index].m_name= name;
	for (int j = 0; j < 10; j++)
	{
		cout << "第" << j + 1 << "位评委请对" << index+1 << "位选手打分:" << endl;
		float temp_score;
		cin >> temp_score;
		m_p[index].m_scores.push_back(temp_score);
	}
}
void Exa_evaluate_score::summarizing(int index)
{
	sort(m_p[index].m_scores.begin(), m_p[index].m_scores.end());
	cout << "最低分为:" << m_p[index].m_scores.front() << endl;
	cout << "最高分为:" << m_p[index].m_scores.back() <<  endl;
	m_p[index].m_scores.pop_back();
	m_p[index].m_scores.pop_front();
	float sum = 0;
	for (deque::iterator it = m_p[index].m_scores.begin(); it != m_p[index].m_scores.end(); it++)
	{
		sum += *it;
	}
	cout << "去除最低分最高分后平均分为:" <<(float)sum / m_p[index].m_scores.size() << endl;

}
int main()
{

	Exa_evaluate_score e;
	for (int i = 0; i < 2; i++)
	{
		e.eval(i);
		e.summarizing(i);
	}
	
	system("pause");
	return 0;
}

运行结果:

 7 STL_第9张图片

2.5stack 容器

2.5.1基本概念

FILO(First In Last Out)

2.5.2stack构造函数

  • stack stk; //stack采用模板类实现, stack对象的默认构造形式

  • stack(const stack &stk); //拷贝构造函数

2.5.3stack赋值函数

  • stack& operator=(const stack &stk); //重载等号操作符

2.5.4stack出栈、入栈、取栈顶

  • push(elem); //向栈顶添加元素

  • pop(); //从栈顶移除第一个元素

  • top(); //返回栈顶元素

2.5.5stack判空、获取大小

  • empty(); //判断堆栈是否为空

  • size(); //返回栈的大小

2.6queue容器

2.6.1queue基本概念

FIFO(First In First Out)

常用函数:尾入头出

7 STL_第10张图片

2.6.2queue构造函数

  • queue que; //queue采用模板类实现,queue对象的默认构造形式

  • queue(const queue &que); //拷贝构造函数

2.6.7queue赋值操作

  • queue& operator=(const queue &que); //重载等号操作符

2.6.8queue入队、出队、获取队尾对头元素

  • push(elem); //往队尾添加元素

  • pop(); //从队头移除第一个元素

  • back(); //返回最后一个元素

  • front(); //返回第一个元素

2.6.9queue判空、获取大小

  • empty(); //判断堆栈是否为空

  • size(); //返回栈的大小

 2.7list容器

2.7.1list基本概念

双向循环链表:list容器的迭代器是双向迭代器,不支持随机访问!

7 STL_第11张图片

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器  

list的优点:

  • 采用动态存储分配,不会造成内存浪费和溢出

  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

list的缺点:

  • 链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大

STL中List和vector是两个最常被使用的容器,各有优缺点

2.7.2 list构造函数

  • list lst; //list采用采用模板类实现,对象的默认构造形式:

  • list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。

  • list(n,elem); //构造函数将n个elem拷贝给本身。

  • list(const list &lst); //拷贝构造函数。

2.7.3 list赋值操作

  • assign(beg, end); //将迭代器[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

  • list& operator=(const list &lst); //重载等号操作符

2.7.4 list交换操作

swap(lst); //将lst与本身的元素互换。

注:不要求两个交换的list的数据个数相同!

2.7.5 list获取大小、判空、更改容量

  • size(); //返回容器中元素的个数

  • empty(); //判断容器是否为空

  • resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 

                                        //如果容器变短,则末尾超出容器长度的元素被删除。

2.7.6 list插入与删除

  • push_back(elem);//在容器尾部加入一个元素

  • pop_back();//删除容器中最后一个元素

  • push_front(elem);//在容器开头插入一个元素

  • pop_front();//从容器开头移除第一个元素

  • insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。

  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。

  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。

  • clear();//移除容器的所有数据

  • erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。

  • erase(pos);//删除pos位置的数据,返回下一个数据的位置。

  • remove(elem);//删除容器中所有与elem值匹配的元素。

2.7.7 list 获取第一个元素、最后一个元素

list不支持随机访问,即无 [] ,at等随机访问的方法;

  • front(); //返回第一个元素。

  • back(); //返回最后一个元素。

 2.7.8 list反转和排序

  • reverse(); //反转链表

  • sort(); //链表排序 参数为一个回调函数,其中声明了排序次序即可更改默认 次序(从小到大)的次序。

L.sort(myCompare); //指定规则,从大到小      

bool myCompare(int val1 , int val2)
{
    return val1 > val2;
}                     

2.7.9 list排序案例

案例描述:将NuiMa自定义数据类型进行排序,NuiMa中属性有姓名、身份排名、薪资水平

排序规则:按照身份排名进行升序,如果身份排名相同按照薪资水平进行升序

代码示例:

//.h
#pragma once
#include "string"
#include "list"
using namespace std;
//牛马类
class NiuMa
{
public:
	NiuMa(string name,int salary,int status)
	{
		m_name = name;
		m_status = status;
		m_salary = salary;
	};
public:
	string m_name;

	int m_salary;
	int m_status;
};
class list_sort_niuma
{
public:
	list m_NM;
};


//.cpp
#include "list_sort_niuma.h"
#include "iostream"

bool sort_relu(NiuMa &nm1 , NiuMa &nm2)
{
	if (nm1.m_status == nm2.m_status)
	{
		return nm1.m_salary > nm2.m_salary;
	}
	return nm1.m_status < nm2.m_status;
}
int main()
{
	NiuMa nm1("小牛马1",5,1);
	NiuMa nm2("小牛马2", 50, 2);
	NiuMa nm3("小牛马3", 50, 2);
	NiuMa nm4("小牛马4", 500, 3);
	NiuMa nm5("小牛马5", 500, 1);
	NiuMa nm6("小牛马6", 5000, 1);
	list_sort_niuma lsn;
	lsn.m_NM.push_back(nm1);
	lsn.m_NM.push_back(nm2);
	lsn.m_NM.push_back(nm3);
	lsn.m_NM.push_back(nm4);
	lsn.m_NM.push_back(nm5);
	lsn.m_NM.push_back(nm6);
	cout << "排序前:" << endl;
	for (list::iterator it = lsn.m_NM.begin(); it != lsn.m_NM.end(); it++)
	{
		cout << "姓名: " << it->m_name << " 社会地位排名: " << it->m_status
			<< " 薪资水平: " << it->m_salary << endl;
	}
	lsn.m_NM.sort(sort_relu);
	cout << "排序后:" << endl;
	for (list::iterator it = lsn.m_NM.begin(); it != lsn.m_NM.end(); it++)
	{
		cout << "姓名: " << it->m_name << " 社会地位排名: " << it->m_status
			<< " 薪资水平: " << it->m_salary << endl;
	}
	system("pause");
	return 0;
}

运行结果:

7 STL_第12张图片

2.8set、multiset 容器

2.8.1set及multiset的基本概念和区别

简介所有的元素会被插入后自动进行排序

本质:关联式容器,底层二叉树实现

set与multiset区别:

  1. set不允许有重复元素
  2. multiset允许有重复元素

注:两个包含头文件,只需包含set即可,即#include ”set“;

2.8.2set构造函数

  • set st; //默认构造函数:

  • set(const set &st); //拷贝构造函数

2.8.3set赋值操作

  • set& operator=(const set &st); //重载等号操作符

2.8.4set判空、获取大小、交换

  • size(); //返回容器中元素的数目

  • empty(); //判断容器是否为空

  • swap(st); //交换两个集合容器

2.8.5set插入与删除

  • insert(elem); //在容器中插入元素。

  • clear(); //清除所有元素

  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。

  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

  • erase(elem); //删除容器中值为elem的元素。

2.8.6set查找与统计

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();

  • count(key); //统计key的元素个数

2.8.7set、multiset的区别

  • set不可以插入重复数据,而multiset可以

  • set插入数据的同时会返回插入结果,表示插入是否成功

  • multiset不会检测数据,因此可以插入重复数据

2.8.8pair对组创建

成对出现的数据,利用对组可返回两个数据

对组创建方式:

pair p (val1,val2);

pair p = make_pair(val1,val2);

代码示例:

pair p(string("Tom"), 20);

pair p2 = make_pair("Jerry", 10);

2.8.9set排序

2.8.9.1内置数据类型排序

主要技术点:

  • 利用仿函数,可以改变排序规则

  • 注意:一定在插入之前就利用仿函数进行指定排序顺序

代码示例:

#include "set"
class MyCompare 
{
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};
void test01() 
{    
	set s1;
	s1.insert(10);
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(50);

	//默认从小到大
	for (set::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	//指定排序规则
	set s2;
	s2.insert(10);
	s2.insert(40);
	s2.insert(20);
	s2.insert(30);
	s2.insert(50);

	for (set::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}
2.8.9.2自定义数据类型排序 

对于自定义数据类型,set必须指定排序规则才可以插入数据

代码示例:

#include 
#include 

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;

};
class comparePerson
{
public:
	bool operator()(const Person& p1, const Person &p2)
	{
		//按照年龄进行排序  降序
		return p1.m_Age > p2.m_Age;
	}
};

void test01()
{
	set s;

	Person p1("刘备", 23);
	Person p2("关羽", 27);
	Person p3("张飞", 25);
	Person p4("赵云", 21);

	s.insert(p1);
	s.insert(p2);
	s.insert(p3);
	s.insert(p4);

	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;
	}
}
int main() {

	test01();

	system("pause");

	return 0;
}

2.9map、multimap容器

2.9.1map基本概念

简介:

  •  map中所有的元素都是pair
  • pair中第一个元素为key,起到索引作用,第二个元素为value
  • 所有的元素会根据元素key自动排序

本质:

  • map/multimap属于关联式容器,底层结构是用二叉树实现

优点:

  • 可以根据key值快速找到value值

map和multimap区别

  • map不允许容器中有重复key值元素

  • multimap允许容器中有重复key值元素

2.9.2map的构造和赋值

  • map mp; //map默认构造函数:

  • map(const map &mp); //拷贝构造函数

  • map& operator=(const map &mp); //重载等号操作符

void test01()
{
	mapm; //默认构造
	m.insert(pair(1, 10));
	m.insert(pair(2, 20));
	m.insert(pair(3, 30));
	printMap(m);

	mapm2(m); //拷贝构造
	printMap(m2);

	mapm3;
	m3 = m2; //赋值
	printMap(m3);
}

2.9.3map判空、获取大小、交换

  • size(); //返回容器中元素的数目

  • empty(); //判断容器是否为空

  • swap(st); //交换两个集合容器

2.9.4map插入、删除

  • insert(elem); //在容器中插入元素。

  • clear(); //清除所有元素

  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。

  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

  • erase(key); //删除容器中值为key的元素。

void test01()
{
	//插入
	map m;
	//第一种插入方式-对组方式一
	m.insert(pair(1, 10));
	//第二种插入方式-对组方式二
	m.insert(make_pair(2, 20));
	//第三种插入方式,不常用
	m.insert(map::value_type(3, 30));
	//第四种插入方式
    //若key不存在则,会创建一个key为该值,value为默认参数的数据,不好
    //所以[]常用于根据key获取value
	m[4] = 40; 
	printMap(m);

	//删除
	m.erase(m.begin());
	printMap(m);
    
    //按照key值删除
	m.erase(3);
	printMap(m);

	//清空
	m.erase(m.begin(),m.end());
	m.clear();
	printMap(m);
}

2.9.5 map查找与统计

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();

  • count(key); //统计key的元素个数

注意:

  • 查找 --- find (返回的是迭代器)

  • 统计 --- count (对于map,结果为0或者1)由于map不允许有重复的key对组!multimap而言就是具体的个数。

2.9.6map排序

  • map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则

主要技术点:

  • 利用仿函数,可以改变排序规则

代码示例:

#include 
​
class MyCompare {
public:
    bool operator()(int v1, int v2) {
        return v1 > v2;
    }
};
​
void test01() 
{
    //默认从小到大排序
    //利用仿函数实现从大到小排序
    map m;
​
    m.insert(make_pair(1, 10));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(3, 30));
    m.insert(make_pair(4, 40));
    m.insert(make_pair(5, 50));
​
    for (map::iterator it = m.begin(); it != m.end(); it++) {
        cout << "key:" << it->first << " value:" << it->second << endl;
    }
}
int main() {
​
    test01();
​
    system("pause");
​
    return 0;
}

总结:

  • 利用仿函数可以指定map容器的排序规则

  • 对于自定义数据类型,map必须要指定排序规则,同set容器

2.9.7map案例

案例描述:

  • 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作

  • 员工信息有: 姓名 工资组成;部门分为:策划、美术、研发

  • 随机给10名员工分配部门和工资

  • 通过multimap进行信息的插入 key(部门编号) value(员工)

  • 分部门显示员工信息

代码示例:

//.h
#pragma once

#include 
#include 
#include "string"
#include "vector"
#include "map"
using namespace std;
class employer
{
public:
	string m_Name;
	int m_DepId;
	float m_Salary;
public:
	employer(string name)
	{
		m_Name = name;
		m_DepId = rand() % 3;
		// 创建一个随机数引擎
		std::random_device rd;
		std::mt19937 gen(rd());

		// 定义浮点数范围
		float lower_bound = 0.0f;
		float upper_bound = 100.0f;

		// 创建一个均匀分布的随机数生成器
		std::uniform_real_distribution dist(lower_bound, upper_bound);

		// 生成随机浮点数
		m_Salary  = dist(gen);
		
	}
};
class exp_map
{
public:
	vector m_emp;
	multimap m_DepMap;
};


//.cpp
#include "exp_map.h"
#include "iostream"
using namespace std;
#define CEHUA  0
#define MEISHU 1
#define YANFA  2
void insert_exp(exp_map &em)
{
	employer e1("A");
	employer e2("B");
	employer e3("C");
	employer e4("D");
	employer e5("E");
	employer e6("F");
	employer e7("G");
	employer e8("H");
	employer e9("I");
	employer e10("J");
	
	em.m_emp.push_back(e1);
	em.m_emp.push_back(e2);
	em.m_emp.push_back(e3);
	em.m_emp.push_back(e4);
	em.m_emp.push_back(e5);
	em.m_emp.push_back(e6);
	em.m_emp.push_back(e7);
	em.m_emp.push_back(e8);
	em.m_emp.push_back(e9);
	em.m_emp.push_back(e10);
}
void insert_multimap(exp_map& em)
{
	for (vector::iterator it = em.m_emp.begin(); it != em.m_emp.end(); it++)
	{
		em.m_DepMap.insert(pair((*it).m_DepId,*it));
	}
}

void show_dep_emp(multimap &m)
{

    //map会按照key进行排序,因此返回pos即第一个符合的位置,其后count个均为其满足条件的结果
	cout << "策划部门:" << endl;
	multimap::iterator pos = m.find(CEHUA);
	int count = m.count(CEHUA);
	int index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "美术部门: " << endl;
	pos = m.find(MEISHU);
	count = m.count(MEISHU); // 统计具体人数
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "研发部门: " << endl;
	
	//range是一个符合find条件的迭代器集合
	auto range = m.equal_range(YANFA);
	//range.first 指向范围的开始(第一个匹配元素),而 range.second 则指向范围的末尾(最后一个匹配元素的下一个位置)
	//auto 用于自动推导变量的类型。使用 auto 可以使编译器自动推断变量的类型,而不需要手动指定
	for (auto pos = range.first; pos != range.second; ++pos) {
		cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
	}
	


}
int main()
{
	exp_map em;
	insert_exp(em);
	insert_multimap(em);
	show_dep_emp(em.m_DepMap);
	system("pause");
	return 0;
}

运行结果:

 7 STL_第13张图片

3、函数对象

3.1函数对象概念

概念:

  • 重载函数调用操作符的类,其对象常称为函数对象

  • 函数对象使用重载的()时,行为类似函数调用,也叫仿函数

本质:

函数对象(仿函数)是一个,不是一个函数

特点:

  • 函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值

  • 函数对象超出普通函数的概念,函数对象可以有自己的状态

  • 函数对象可以作为参数传递

3.2函数对象的使用

1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值

其实就是仿函数,本质是一个类重载了()运算符,然后通过匿名对象调用()。

2、函数对象可以有自己的状态

其实就是因为其本质是类,所以可以拥有成员变量即“自己的状态标识”

3、函数对象可以作为参数传递

其实就是因为其本质是类,则参数即为该类的对象实例!

3.3谓词

3.3.1谓词概念

  • 返回bool类型的仿函数被称为谓词
  • operator()重载()运算符,接受一个参数,那么叫一元谓词
  • operator()重载()运算符,接受两个参数,那么叫二元谓词

目前看与仿函数挂钩

3.4内建函数对象-可直接拿来用的仿函数

3.4.1概念

STL内建了一些函数对象

  • 算术仿函数
  • 关系仿函数
  • 逻辑仿函数

注意:

需要引入头文件 #include

3.4.2算术仿函数

仿函数原型:

  • template T plus //加法仿函数

  • template T minus //减法仿函数

  • template T multiplies //乘法仿函数

  • template T divides //除法仿函数

  • template T modulus //取模仿函数

  • template T negate //取反仿函数-一元仿函数,其余均为二元仿函数

//negate
void test01()
{
	negate n;
	cout << n(50) << endl;
}

//plus
void test02()
{
	plus p;
	cout << p(10, 20) << endl;
}

3.4.3关系仿函数

  • template bool equal_to //等于

  • template bool not_equal_to //不等于

  • template bool greater //大于

  • template bool greater_equal //大于等于

  • template bool less //小于

  • template bool less_equal //小于等于

//伪代码
class MyCompare
{
public:
	bool operator()(int v1,int v2)
	{
		return v1 > v2;
	}
};
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数  大于仿函数
sort(v.begin(), v.end(), greater());

3.4.5逻辑仿函数

  • template bool logical_and //逻辑与

  • template bool logical_or //逻辑或

  • template bool logical_not //逻辑非

逻辑仿函数实际应用较少,了解即可

4、STL-常用算法

4.1常用头文件

  • 算法主要是由头文件 组成。

  • 是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等

  • 体积很小,只包括几个在序列上面进行简单数学运算的模板函数

  • 定义了一些模板类,用以声明函数对象。

4.2常用遍历算法

4.2.1for_each 很常用

功能:遍历容器元素

for_each(iterator beg, iterator end, _func);

// beg 开始迭代器

// end 结束迭代器

// _func 函数或者函数对象

4.2.2transform

功能:搬运容器到另一个容器中

transform(iterator beg1, iterator end1, iterator beg2, _func);

//beg1 源容器开始迭代器

//end1 源容器结束迭代器

//beg2 目标容器开始迭代器

//_func 函数或者函数对象,这可以对搬运的数据进行一些运算,实现在仿函数中

//仿函数,不对搬运数据进行处理,直接返回
class TransForm
{
public:
	int operator()(int val)
	{
		return val;
	}

};

4.3常用查找算法

4.3.1find

功能:查找指定元素(内置类型、自定义类型),找到返回指定元素的迭代器,找不到返回结束迭代器end()

find(iterator beg, iterator end, value);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// value 查找的元素

注意:利用find可以在容器中找指定的元素,返回值是迭代器

           对于自定义数据类型应该重载operator==,告诉如何对比查找。

//重载==
	bool operator==(const Person& p) 
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) 
		{
			return true;
		}

4.3.2find_if

功能:按照条件查找元素

find_if(iterator beg, iterator end, _Pred);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 函数或者谓词(返回bool类型的仿函数)

4.3.3adjacent_find

功能:查找相邻重复元素

adjacent_find(iterator beg, iterator end);

// 查找相邻重复元素,返回相邻元素的第一个位置的迭代器

// beg 开始迭代器

// end 结束迭代器

4.3.4count

功能:统计元素个数

count(iterator beg, iterator end, value);

// 统计元素出现次数

// beg 开始迭代器

// end 结束迭代器

// value 统计的元素

注意:value也可以是自定义数据类型,需要在自定义数据类型重载operator==

bool operator==(const Person & p)
	{
		if (this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

4.3.5count_if

功能:按条件统计元素个数

count_if(iterator beg, iterator end, _Pred);

// 按条件统计元素出现次数

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词

4.3.6binary_search

功能:查找指定元素是否存在

bool binary_search(iterator beg, iterator end, value);

// 查找指定的元素,查到 返回true 否则false

// 注意: 在无序序列中不可用,因为底层是二分查找

// beg 开始迭代器

// end 结束迭代器

// value 查找的元素

4.4常用排序算法

4.4.1sort 常用

功能:对容器内元素进行排序

sort(iterator beg, iterator end, _Pred);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词

4.4.2random_shuffle

功能:洗牌、指定范围的元素打乱次序

random_shuffle(iterator beg, iterator end);

// 指定范围内的元素随机调整次序

// beg 开始迭代器

// end 结束迭代器

注意:用之前需要加种子,才能真实随机

随机种子:srand((unsigned int) time(NULL));

4.4.3merge

功能:两个容器元素合并,并存储到另一个容器中

merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 容器元素合并,并存储到另一容器中

// 注意: 两个容器必须是有序的,记得给放入的容器resize扩容一下。

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

4.4.4reverse

功能:容器内元素进行反转

reverse(iterator beg, iterator end);

// 反转指定范围的元素

// beg 开始迭代器

// end 结束迭代器

4.5常用拷贝喝替换函数

4.5.1copy

功能:容器内指定范围的元素拷贝到另一容器中

copy(iterator beg, iterator end, iterator dest);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// dest 目标起始迭代器

4.5.2replace

功能:将容器内指定范围的旧元素替换为新的元素

replace(iterator beg, iterator end, oldvalue, newvalue);

// 将区间内旧元素 替换成 新元素

// beg 开始迭代器

// end 结束迭代器

// oldvalue 旧元素

// newvalue 新元素

4.5.3replace_if

功能:

将区间内满足条件的元素,替换成指定元素

replace_if(iterator beg, iterator end, _pred, newvalue);

// 按条件替换元素,满足条件的替换成指定元素

// beg 开始迭代器

// end 结束迭代器

// _pred 谓词

// newvalue 替换的新元素

4.5.4swap

功能:互换两个容器的元素

swap(container c1, container c2);

// 互换两个容器的元素

// c1容器1

// c2容器2

注意:两个容器数据类型必须相同

4.6常用算术生成算法

4.6.1accumulate

功能:计算区间内容器元素累计总和

accumulate(iterator beg, iterator end, value);

// 计算容器元素累计总和

// beg 开始迭代器

// end 结束迭代器

// value 起始值              一般为0

注意:accumulate使用时头文件注意是 numeric,这个算法很实用

4.6.2fill

功能:向容器中填充指定的元素

fill(iterator beg, iterator end, value);

// 向容器中填充元素

// beg 开始迭代器

// end 结束迭代器

// value 填充的值

4.7常用集合算法-交并差集

4.7.1set_intersectionn

功能:求两个容器的交集

set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的交集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

注意:

  • 求交集的两个集合必须的有序序列

  • 目标容器开辟空间需要从两个容器中取小值

  • set_intersection返回值既是交集中最后一个元素的位置

遍历用返回的最后的迭代器itEnd.

set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());

	for_each(vTarget.begin(), itEnd, myPrint());
	cout << endl;

4.7.2set_union

功能:求并集

set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的并集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

注意:

  • 求并集的两个集合必须的有序序列

  • 目标容器开辟空间需要两个容器相加

  • set_union返回值既是并集中最后一个元素的位置

4.7.3set_difference

功能:两个集合差集

set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的差集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

注意:

  • 求差集的两个集合必须的有序序列

  • 目标容器开辟空间需要从两个容器取较大值

  • set_difference返回值既是差集中最后一个元素的位置

你可能感兴趣的:(C++,c++,开发语言)