STL(标准模板库)的使用

1. STL初识

1.1 STL的诞生

  • C++的面向对象和泛型编程思想,目的就是复用性的提高
  • 为了建立数据结构和算法的一套标准,诞生了STL

1.2 STL基本概念

  • STL(标准模板库)
  • STL从广义上分为:容器、算法、迭代器
  • 容器算法之间通过迭代器进行无缝连接
  • STL几乎所有的代码都采用了模板类或模板函数

1.3 STL六大组件

容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  • 容器:各种数据结构,如vector,list,deque,set,map等,用来存放数据
  • 算法:各种常用的算法,如sort,find,copy,for_each等
  • 迭代器:扮演了容器和算法之间的胶合剂
  • 仿函数:行为类似函数,可作为算法的某种策略
  • 适配器:一种用来修饰容器或者仿函数或迭代器接口的
  • 空调配置器:负责空间的配置与管理

1.4 STL容器、算法、迭代器

容器:STL容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组,链表,树,栈,队列,集合,映射表等

这些容器分为 序列式容器和关联式容器 两种:

  • 序列式容器:强调值的排序,序列式容器中的每个元素都有固定的位置
  • 关联式容器:二叉树结构,各个元素之间没有严格的物理上的顺序关系

算法

有限的步骤,解决逻辑上或数学上的问题,算法可以分为质变算法和非质变算法

  • 质变算法:是指运算过程中会更改区间内的元素的内容,例如拷贝、替换、删除等

  • 非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等

迭代器:算法和容器之间的桥梁

提供一种方法,使之能够依序访问某个容器中所含的各个元素,而又无需暴漏该容器的内部表示方式

每个容器都有自己专属的迭代器

迭代器使用非常类似于指针,初始阶段可以理解为指针

迭代器种类

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

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

1.5 容器算法迭代器初识

1. vector存放内置数据类型

STL中最常用的容器是vector,可以理解为数组

容器算法迭代器
vectorfor_eachvector::iterator

示例:

#include<vector>
#include<algorithm>	//标准算法头文件

void myPrint(int val)
{
	cout << val << endl;
}

void test01()
{
	//创建了一个vector容器---数组
	vector<int> v;

	//容器中插入数据 vector内置 .push_back()尾插法
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	//通过迭代器访问容器中的数据
	vector<int>::iterator itBegin = v.begin();	//起始迭代器,指向容器中第一个元素
	vector<int>::iterator itEnd = v.end();	//结束迭代器,指向容器中最后一个元素的下一个位置
	//第一种遍历方式
	while (itBegin != itEnd)
	{
		//对指针解引用
		cout << *itBegin << endl;
		itBegin++;
	}

	//第二种遍历方式
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}

	//第三种遍历方式	利用STL中提供的遍历算法for_each 需要导入标准算法头文件
	for_each(v.begin(), v.end(), myPrint);

}
int main()
{

	test01();
	system("pause");
	return 0;
}

2. Vector存放自定义数据类型

示例:

#include<vector>

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

//存放自定义数据类型
void test01()
{
	vector<Person> v;

	Person p1("hututu", 23);
	Person p2("lututu", 23);
	Person p3("eututu", 23);
	Person p4("mututu", 23);
	Person p5("pututu", 23);

	//向容器中尾插数据
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);

	//遍历容器中数据
	//it是Person*,解引用后是Person
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		/*cout << "姓名:" << (*it).m_name << " "
			<< "年龄:" << (*it).m_age << endl;*/
		//it可以看作指针
		cout << "姓名:" << it->m_name << " "
			<< "年龄:" << it->m_age << endl;
	}
}

//存放自定义数据类型指针
void test02()
{
	//容器中存放的是地址
	vector<Person*> v;

	Person p1("hututu", 23);
	Person p2("lututu", 23);
	Person p3("eututu", 23);
	Person p4("mututu", 23);
	Person p5("pututu", 23);

	//向容器中尾插数据
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	v.push_back(&p4);
	v.push_back(&p5);

	//遍历容器
	//it是Person**,解引用的(*it)是Person*
	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名:" << (*it)->m_name << "\t" << "年龄:"
			<< (*it)->m_age << endl;
	}
}

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

注意:

- vector<Person>::iterator it,it是Person*,解引用的(*it)是Person
- vector<Person*>::iterator it,it是Person**,解引用的(*it)是Person*

3. Vector容器嵌套容器

学习容器嵌套容器,将所有数据进行遍历输出

示例:

#include<vector>

void test01()
{
	vector<vector<int>> v;

	//创建小容器
	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	vector<int> v4;

	//向小容器中添加数据
	for (int i = 0; i < 4; i++)
	{
		v1.push_back(i + 1);
		v2.push_back(i + 2);
		v3.push_back(i + 3);
		v4.push_back(i + 4);
	}

	//将小容器插入到大容器中
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);

	//通过大容器 将所有数据遍历一遍
	for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
	{
		//(*it)是vector<int>类型的数据容器
		for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
		{
			//*vit 是int类型的
			cout << *vit << " ";
		}
		cout << endl;
	}
}

int main()
{
	test01();
	system("pause");
	return 0;
}
--------------------------------------------------------------------------------------
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
请按任意键继续. . .

2. STL-常用容器

2.1 string 容器

1. string 容器基本概念

本质

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

string和char 区别*:

  • char * 是一个指针(C中string的本质)
  • string是一个类,类内部封装了char* ,管理这个字符串,是一个char*类型的数据容器

特点

  • string内部封装了很多成员方法
  • string管理char*所分配的内存,不用担心复制越界或者取值越界等,由类内部进行负责

2. string 构造函数

构造函数原型

string();					//构建一个空的字符串
string(const char* s);	  	//使用字符串s进行初始化
string(const string& str);	//使用一个string对象初始化另一个string对象
string(int n,char c);		//使用n个字符初始化
void test01()
{
	string s1;	//默认构造
	
    //把c_string转化成了string
	const char* str = "nibukunwokun";
	string s2(str);
	cout << "s2=" << s2 << endl;

    //调用拷贝构造函数
	string s3(s2);
	cout << "s3=" << s3 << endl;

	string s4(6, 'a');
	cout << "s4=" << s4 << endl;

}
int main()
{
	test01();
	system("pause");
	return 0;
}
-----------------------------------------------------------
s2=nibukunwokun
s3=nibukunwokun
s4=aaaaaa
请按任意键继续. . .

3. string 赋值操作

功能描述:给string字符串进行赋值

赋值的函数原型

函数注释
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赋值给当前的字符串

示例:

#include<vector>

void test01()
{
	//string & operator=(const char* s);
	string str1;
	str1 = "hello world";
	cout << "str1= " << str1 << endl;

	//string & operator=(const string s);
	string str2;
	str2 = str1;
	cout << "str2= " << str2 << endl;

	//string & operator=(char  c); 
	string str3;
	str3 = 'a';
	cout << "str3= " << str3 << endl;

	//string & assign(const char * s); 
	string str4;
	str4.assign("hututu");
	cout << "str4= " << str4 << endl;

	string str5;
	str5.assign("hututu", 3);
	cout << "str5= " << str5 << endl;

	string str6;
	str6.assign(str5);
	cout << "str6= " << str6 << endl;

	string str7;
	str7.assign(10, 'a');
	cout << "str7= " << str7 << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
------------------------------------------
str1= hello world
str2= hello world
str3= a
str4= hututu
str5= hut
str6= hut
str7= aaaaaaaaaa
请按任意键继续. . .

4. string 字符串拼接

功能描述:实现字符串末尾拼接字符串

函数原型

函数注释
string & opertor+=(const char* str);重载+=操作符
string & opertor+=(const char c);重载+=操作符
string & opertor+=(const string & str);重载+=操作符
string & append(const char* s);把字符串s拼接到当前字符串结尾
string & append(const char* s, int n);把字符串s的前n个字符连接到当前字符串结尾
string & append(const string &s);同string & opertor+=(const char* str);
string & append(const string &s, int pos, int n);字符串s中从pos开始的n个字符连接到字符串结尾

示例:

void test01()
{
	//重载+=运算符
	string str1 = "你";
	str1 += "不困";
	cout << str1 << endl;

	str1 += ',';
	cout << str1 << endl;

	string str2 = "我困";

	str1 += str2;
	cout << "str1=" << str1 << endl;

	//append函数
	string str3 = "hututu";
	str3.append(" and");
	cout << "str3=" << str3 << endl;

	str3.append(" xiaomei abdjs", 8);
	cout << "str3=" << str3 << endl;

	//str3.append(str2);
	//cout << "str3=" << str3 << endl;

	string str4 = "abcdefg";
	//从pos位置开始,截取n个元素
	str3.append(str4, 0, 3);
	cout << "str3=" << str3 << endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

5. string 查找和替换

功能描述

  • 查找:查找指定字符是否存在
  • 替换:在指定的位置替换字符串

函数原型

函数注释
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 c, int pos=0)const;查找字符c最后一次出现位置
int rfind(const char *s,int pos,int n)const;从pos查找s的前n个字符最后一次位置
string & replace(int pos, int n, const string & str);替换从pos开始n个字符为字符串str
string & replace(int pos,int n,const char *s);替换从pos开始的n字符为字符串s

示例

#include<vector>

void test01()
{
	string str1 = "hututugaagag";

	int pos1 = str1.find("hu");
	if (pos1 == -1)
		cout << "未找到字符串" << endl;
	else
		cout << "字符串第一次出现的位置是:" << pos1 << endl;
	//cout << "pos1=" << pos1 << endl;	//2

	//rfind
	//rfind是从右往左查找,find是左往右查找
	int pos2 = str1.rfind("hu");
	cout << "pos2=" << pos2 << endl;
}

//替换
void test02()
{
	string str1 = "abcdefg";
	//从1号位置起,3个字符替换为1111
	str1.replace(1, 3, "1111");			
	cout << str1 << endl;		//a1111efg
}

总结

  • find查找是从左往右,rfind从右往左
  • find找到字符串后返回查找的第一个字符位置,找不到返回-1
  • replace在替换时,要指定从哪个位置开始起,多少个字符,替换成什么样的字符串

6. string 字符串比较

功能描述:字符串之间的比较

比较方式:字符串比较是按照字符的ASCII码进行对比

= 返回0
> 返回1
< 返回-1

函数原型

函数注释
int compare(const string &s)const;与字符串s比较
int compare(const char *s)const;与字符串s比较

示例

#include<vector>

void test01()
{
	string str1 = "hello";
	string str2 = "hello";

	if (str1.compare(str2) == 0)
		cout << "str1==str2" << endl;
	else if (str1.compare(str2) == 1)
		cout << "str1>str2" << endl;
	else
		cout << "str1<str2" << endl;

}

7. string 字符存取

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

函数注释
char& operator[](int n);通过[]方式取字符
char& art(int n);通过at方式获取字符

示例:

#include<vector>

void test01()
{
	string str1 = "hello";

	//cout << "str1=" << str1 << endl;
	//依次输出字符串中字符
	//1、通过[]方式访问单个字符
	for (int i = 0; i < str1.size(); i++)
		cout << str1[i] << " ";
	cout << endl;

	//2、通过at方式访问单个字符
	for (int i = 0; i < str1.size(); i++)
		cout << str1.at(i) << " ";
	cout << endl;

	//修改单个字符
	str1[0] = 'a';
	cout << "str1=" << str1 << endl;	//str1=aello

	str1.at(1) = 'a';
	cout << "str1=" << str1 << endl;	//str1=aallo
}

8. string 插入和删除

功能描述:对string字符串进行插入和删除字符操作

函数原型:

函数注释
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个字符

示例:

#include<vector>

void test01()
{
	string str = "hello";

	//插入
	str.insert(1, "111");
	cout << "str=" << str << endl;		//str=h111ello

	//删除
	str.erase(1, 3);
	cout << "str=" << str << endl;		//str=hello
}

9. string 子串获取

功能描述:从字符串中获取想要的子串

函数原型

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

示例

#include<vector>

void test()
{
	string str = "abcdefg";

	string subStr = str.substr(1, 3);
	cout << subStr << endl;		//bcd
}
void test02()
{
	string email = "nibukunwokun@sina.com";
	//从邮件地址中获取用户信息
	int pos = email.find("@");	//返回@的下标地址
	string userName = email.substr(0, pos);
	cout << userName << endl;		//nibukunwokun
}

2.2 vector 容器

1. vector 基本概念

功能

  • vector数据容器和数组相似,也称为单端数组

vector与普通数组的区别

  • 不同指出在于数组是静态空间,而vector可以动态扩展

动态扩展

  • 并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间

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

2. vector 构造函数

功能描述

  • 创建vector容器

函数原型

函数原型注释
vector v;采用模板实现类实现,默认构造函数
vector v(v.begin(), v.end()) ;将v [begin(),end()) 区间(前闭后开)中的元素拷贝到自身
vector v(n, elem);构造函数将n个elem拷贝给本身
vector v(const vector &vec);拷贝构造函数

示例

#include<vector>

void printVector(vector<int> &v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
		cout << *it << " ";
	cout << endl;
}
void test01()
{
	vector<int> v1;	// 默认构造,无参构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);

	//通过区间的方式进行构造
	vector<int>v2(v1.begin(), v1.end());
	printVector(v2);

	//n个elem方式构造
	vector<int>v3(10, 88);
	printVector(v3);

	//拷贝构造
	vector<int>v4(v3);
	printVector(v4);
}
-----------------------------------------------------
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
88 88 88 88 88 88 88 88 88 88
88 88 88 88 88 88 88 88 88 88
请按任意键继续. . .

3. vector 赋值操作

功能描述

  • 给vector容器进行赋值

函数原型

函数原型注释
vector& operator=(const vector &vec);重载等号操作符
assign(beg, end);将[beg,end]区间中的数据拷贝赋值给本身
assign(n, elem);将n个elem拷贝赋值给本身

示例

#include<vector>
void test01()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
		v1.push_back(i);
	printVector(v1);

	//赋值 重载=
	vector<int> v2;
	v2 = v1;
	printVector(v2);

	//assign
	vector<int>v3;
	v3.assign(v1.begin(), v1.end());
	printVector(v3);

	vector<int>v4;
	v4.assign(10, 88);
	printVector(v4);
}
-----------------------------------------------
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
88 88 88 88 88 88 88 88 88 88
请按任意键继续. . .

4. vector 容量和大小

功能描述

  • 对vector容器的容量和大小操作

函数原型

函数注释
empty();判断容器是否为空
capacity();容器的容量
size();返回容器中元素的个数
resize(int num);重新指定容器的长度为num,若容器变长,则以默认值填充新位置;若容器变短,则末尾超出容器长度的元素被删除
resize(int num, elem);重新指定容器的长度为num,若容器变长,则以elem值填充新位置 ;若容器变短,则 末尾超出容器长度的元素被删除

示例

void test01()
{
	vector<int>v1;
	for (int i = 0; i < 10; i++)
		v1.push_back(i);
	printVector(v1);

	//.empty()为true,则代表容器为空
	if (v1.empty())
		cout << "v1为空" << endl;
	else
	{
		cout << "v1不为空" << endl;
		cout << "v1的容量是:" << v1.capacity() << endl;
		cout << "v1的大小是:" << v1.size() << endl;	//此时容器中元素个数
	}

	//重新指定大小
	v1.resize(15);
	printVector(v1);
	
	v1.resize(5);
	printVector(v1);
}
-----------------------------------------------
0 1 2 3 4 5 6 7 8 9
v1不为空
v1的容量是:13
v1的大小是:10
0 1 2 3 4 5 6 7 8 9 0 0 0 0 0
0 1 2 3 4
请按任意键继续. . .

5. vector 插入和删除

功能描述:

  • 对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();删除容器中所有元素

示例:

void test01()
{
	vector<int>v1;
	//尾插法
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);
	v1.push_back(50);

	printVector(v1);

	//尾删
	v1.pop_back();
	printVector(v1);

	//插入 第一个参数是迭代器
	v1.insert(v1.begin(), 88);
	printVector(v1);

	v1.insert(v1.begin(), 2, 99);
	printVector(v1);

	//删除 参数也是迭代器
	v1.erase(v1.begin());
	printVector(v1);

	v1.erase(v1.begin(), v1.end());		//类似于 .clear()
	printVector(v1);
}
-----------------------------------
10 20 30 40 50
10 20 30 40
88 10 20 30 40
99 99 88 10 20 30 40
99 88 10 20 30 40

请按任意键继续. . .

6. vector 数据存取

功能描述:

  • 对vector中的数据的存取操作

函数原型:

函数注释
at(int idx);返回索引idx所指的数据
operator[];返回索引idx所指的数据
front();返回容器中第一个数据元素
back();返回容器中最后一个数据元素

示例:

void test01()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
		v1.push_back(i);

	//利用重载[]来访问vector中元素
	for (int i = 0; i < v1.size(); i++)
		cout << v1[i] << " ";
	cout << endl;
	
	//利用at方式访问元素
	for (int i = 0; i < v1.size(); i++)
		cout << v1.at(i) << " ";
	cout << endl;

	//获取第一个元素
	cout << "第一个元素为:" << v1.front() << endl;
	cout << "最后一个元素为:" << v1.back() << endl;
}
-------------------------------------------
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
第一个元素为:0
最后一个元素为:9
请按任意键继续. . .

7. vector 互换容器

功能描述

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

函数原型

函数注释
swap(vec);将vec与本身的元素互换

示例

#include<vector>

void printVector(vector<int>&v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
		cout << *it << " ";
	cout << endl;
}
//基本使用
void test01()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
		v1.push_back(i);

	vector<int>v2;
	for (int i = 10; i > 0; i--)
		v2.push_back(i);

	cout << "交换前:" << endl;
	printVector(v1);
	printVector(v2);

	cout << "交换后:" << endl;
	v1.swap(v2);
	printVector(v1);
	printVector(v2);
}

//实际用途:巧用swap可以收缩内存空间
void test02()
{
	vector<int>v;
	for (int i = 0; i < 100000; i++)
		v.push_back(i);
	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的大小:" << v.size() << endl;

	v.resize(3);	//重新指定大小
	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的大小:" << v.size() << endl;

	//使用swap来收缩内存
	/*
	vector<int>(v) 匿名对象,按照v对其进行初始化
	.swap(v) 类似于指针的交换,相当于将匿名对象容器和v进行交换
	因为匿名对象由编译器自动回收,所以不用担心大量空间被占用
	*/
	vector<int>(v).swap(v);	
	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的大小:" << v.size() << endl;
}
----------------------------------------------
v的容量:138255
v的大小:100000
v的容量:138255
v的大小:3
v的容量:3
v的大小:3
请按任意键继续. . .

8. vector 预留空间

功能介绍:减少vector在动态扩展容量时的扩展次数

函数原型:

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

示例:

#include<vector>

void test01()
{
	vector<int> v;
	//利用reserve来预留空间
	//当数据量很大时,最开始就进行预留空间就可以避免后期不断开辟新空间
	v.reserve(10000);
	int num = 0;
	int *p = NULL;
	for (int i = 0; i < 10000; i++)
	{
		v.push_back(i);
		//每次开辟内存时,首地址都会发生改变,用num记录动态扩展的次数
		if (p != &v[0])
		{
			p = &v[0];
			num++;
		}
	}
	cout << "num=" << num << endl;
}

2.3 deque容器

1. deque容器基本概念

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

deque与vector的区别

  • vector对于头部插入删除效率低,数据量越大,效率越低
  • deque相对而言,对头部插入速度比vector快
  • vector访问元素时的速度会比deque快,这和两者内部实现有关

deque内部工作原理

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

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

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

2. deque构造函数

功能描述:deque容器构造

函数原型

函数原型注释
deque deque T;默认构造形式
deque(beg,end);构造函数将【beg,end)区间中的元素拷贝给本身
deque(n, elem);构造函数将n个elem拷贝给本身
deque(cosnt deque &deq);拷贝构造函数

示例

#include<deque>

//输入参数 const限定只读
void printDeque(const deque<int> &d)
{
	//获取迭代器deque<int>::const_iterator类型同样也是限定只读
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque(d1);

	deque<int> d2(d1.begin(), d1.end());
	printDeque(d2);

	deque<int>d3(10, 100);
	printDeque(d3);

	deque<int>d4(d3);
	printDeque(d4);
}

总结:deque容器和vector容器的构造方式几乎一致

3. deque赋值操作

功能描述:给deque容器进行赋值

函数原型

函数原型注释
deque& operator =(const deque &deq);重载等号操作符
assign(beg,end);将【beg, end)区间中的数据拷贝赋值给本身
assign(n, elem);将n个elem拷贝赋值给本身

示例

#include<deque>

void printDeque(const deque<int> &d);
void test01()
{
	deque<int> d1;
	for (int i = 0; i < 10; i++)
		d1.push_back(i);
	printDeque(d1);

	//重载 = 
	deque<int>d2;
	d2 = d1;
	printDeque(d2);

	deque<int>d3;
	d3.assign(d1.begin(), d1.end());
	printDeque(d3);

	deque<int>d4;
	d4.assign(10, 8);
	printDeque(d4);
}

--------------------------------
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
8 8 8 8 8 8 8 8 8 8

4. deque大小操作

功能描述:对deque容器的大小进行操作

函数原型

函数原型注释
deque.empty();判断容器是否为空
deque.size();返回容器中元素的个数
deque.resize(num);重新指定容器的长度为num,若容器变长,则以默认值填充新位置;若容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem);重新指定容器的长度为num,若容器变长,则以elem重新填充新位置;若容器变短,则末尾超过容器长度的元素被删除。

示例

void test01()
{
	deque<int> d1;
	for (int i = 0; i < 10; i++)
		d1.push_back(i);
	printDeque(d1);

	if (d1.empty())
		cout << "d1为空" << endl;
	else
	{
		cout << "d1不为空" << endl;
		//deque没有容量的概念,因为可以无限放数据
		cout << "d1大小为:" << d1.size() << endl;
	}
	//重新指定大小
	d1.resize(15, 88);
	printDeque(d1);

	d1.resize(5);
	printDeque(d1);	
}
-----------------------------------------
0 1 2 3 4 5 6 7 8 9
d1不为空
d1大小为:10
0 1 2 3 4 5 6 7 8 9 88 88 88 88 88
0 1 2 3 4
请按任意键继续. . .

总结

  • deque没有容量的概念
  • 判断是否为空 - empty
  • 返回元素个数 - size
  • 重新指定个数 - resize

5. deque插入和删除

功能描述:向deque中插入和删除数据

两端插入操作

函数原型注释
push_back(elem);在容器尾部添加一个数据
push_front(elem);在容器头部插入一个数据
pop_back();删除容器最后一个数据
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位置的数据,返回下一个数据的位置

示例

void test01()
{
	deque<int>d1;
	//尾插
	d1.push_back(10);
	d1.push_back(20);
	
	//头插
	d1.push_front(100);
	d1.push_front(200);

	printDeque(d1);

	//尾删
	d1.pop_back();
	printDeque(d1);

	//头删
	d1.pop_front();
	printDeque(d1);
}
----------------------
200 100 10 20
200 100 10
100 10
请按任意键继续. . .
void test02()
{
	deque<int>d1;
	d1.push_back(10);
	d1.push_back(20);
	d1.push_front(100);
	d1.push_front(200);
	printDeque(d1);

	//insert插入
	d1.insert(d1.begin(), 88);
	printDeque(d1);

	d1.insert(d1.begin(), 2, 88);
	printDeque(d1);

	//按照区间进行插入
	deque<int>d2;
	d2.push_back(1);
	d2.push_back(2);
	d2.push_back(3);

	d1.insert(d1.begin(), d2.begin(), d2.end());
	printDeque(d1);	//1 2 3 88 88 88 200 100 10 20
}
-----------------------
200 100 10 20
88 200 100 10 20
88 88 88 200 100 10 20
1 2 3 88 88 88 200 100 10 20
请按任意键继续. . .
void test03()
{
	deque<int>d1;
	d1.push_back(10);
	d1.push_back(20);
	d1.push_front(100);
	d1.push_front(200);
	printDeque(d1);

	//删除
	//d1.erase(d1.begin());
	deque<int>::iterator it = d1.begin();
	it++;	//迭代器向后偏移一位,完成删除第二个元素的作用
	d1.erase(it);
	printDeque(d1);

	//按照区间删除
	d1.erase(d1.begin(), d1.end());	//相当于d1.clear()
	printDeque(d1);
}
---------------------------
200 100 10 20
200 10 20

请按任意键继续. . .

6. deque数据存取

功能描述:对deque中的数据的存取操作

函数原型

函数原型注释
at(int idx);返回索引idx所指的数据
operator[];返回索引idx所指的数据
front();返回容器中第一个数据元素
back();返回容器中最后一个数据元素

示例

void test01()
{
	deque<int>d;
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	d.push_front(8);
	d.push_front(88);
	d.push_front(888);

	//通过[]方式访问元素
	for (int i = 0; i < d.size(); i++)
	{
		cout << d[i] << " ";
	}
	cout << endl;	//888 88 8 10 20 30

	//通过at方式访问元素
	for (int i = 0; i < d.size(); i++)
	{
		cout << d.at(i) << " ";
	}
	cout << endl;	//888 88 8 10 20 30

	cout << "第一个元素为:" << d.front() << endl;
	cout << "最后一个元素为:" << d.back() << endl;
}

7. deque排序

功能描述:利用算法实现对deque容器进行排序

算法

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

示例

#include<algorithm>	//标准算法头文件

void printDeque(const deque<int>&d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
		cout << *it << " ";
	cout << endl;
}
void test01()
{
	deque<int>d;
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	d.push_front(100);
	d.push_front(200);
	d.push_front(300);
	//打印
	printDeque(d);

	sort(d.begin(),d.end());
	cout << "排序后结果:" << endl;
	printDeque(d);
}
------------------------
300 200 100 10 20 30
排序后结果:
10 20 30 100 200 300
请按任意键继续. . .

总结:对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其排序,eg:vector

2.4 stack容器

1.基本概念

stack是一种先进后出(FILO)的数据结构,它只有一个出口

栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为

入栈:栈中进入数据push

出栈:弹出数据pop

2. 常见接口

功能描述:栈容器常用的对外接口

构造函数:

函数注释
stack stk;stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk);拷贝构造函数

赋值操作:

函数注释
stack& operator = (const stack &stk);重载等号操作符

数据存取:

函数注释
push(elem);向栈顶添加元素
pop();从栈顶移除第一个元素
top();返回栈顶元素

大小操作:

函数注释
empty();判断栈顶是否为空
size();返回栈的大小

示例:

using namespace std;

void test01()
{
	stack<int>s;

	//入栈
	s.push(10);
	s.push(20);
	s.push(30);
	s.push(40);

	cout << "栈的大小为:" << s.size() << endl;
	//只要栈不为空,查看栈顶并且执行出栈操作
	while (!s.empty())
	{
		cout << "栈顶元素为:" << s.top() << endl;
		//出栈
		s.pop();
	}
	cout << "栈的大小为:" << s.size() << endl;
}

-------------------
栈的大小为:4
栈顶元素为:40
栈顶元素为:30
栈顶元素为:20
栈顶元素为:10
栈的大小为:0
请按任意键继续. . .

2.5 queue容器

1. 基本概念

  • queue是 一种先进先出(FIFO)的数据结构,它有两个出口

  • 队列容器允许从一端新增元素,从另一端移除元素

  • 队列中只有队头和队尾才可以被外界使用,因此队列不允许遍历行为

  • 入队:队列中进数据push

    出队:队列中出数据pop

2. queue常用接口

功能描述:队列容器常用的对外接口

构造函数:

函数注释
queue que;queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que);拷贝构造函数

赋值操作:

函数注释
queue& operator = (const queue &que);重载等号操作符

数据存取:

函数注释
push(elem);往队尾添加元素
pop();从队头移除第一个元素
back();返回最后一个元素
front();返回第一个元素

大小操作:

函数注释
empty();判断栈是否为空
size();返回栈的大小

示例:

using namespace std;

class Person
{
public:
	Person(string name, int age)
	{
		this->m_name = name;
		this->age = age;
	}
	string m_name;
	int age;
};
void test01()
{
	//创建队列容器
	queue<Person>q;
	Person p1("楚子航", 23);
	Person p2("夏弥", 21);
	Person p3("凯撒", 25);
	Person p4("诺诺", 22);

	//入队
	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);

	//判断只要队列不为空,查看队头,查看队尾,出队
	while (!q.empty())
	{
		cout << "队头姓名:" << q.front().m_name << "年龄:" << q.front().age << endl;
		cout << "队尾姓名:" << q.back().m_name << "年龄:" << q.back().age << endl;

		//出队
		q.pop();
	}
	cout << "队列的大小:" << q.size() << endl;
}
---------------------------
队头姓名:楚子航        年龄:23
队尾姓名:诺诺  年龄:22
队头姓名:夏弥  年龄:21
队尾姓名:诺诺  年龄:22
队头姓名:凯撒  年龄:25
队尾姓名:诺诺  年龄:22
队头姓名:诺诺  年龄:22
队尾姓名:诺诺  年龄:22
队列的大小:0
请按任意键继续. . .

2.6 list容器

1. 基本概念

功能:将数据进行链式存储

  • 链表是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的

  • 链表的组成:链表是由一系列结点组成

  • 结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

  • STL中的链表是一个双向循环链表

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

    list还有个重要的性质,插入和删除操作并不会造成原有list迭代器的失效,这在vector是不成立的

list优缺点

  • 优点:

    • 可以对任意位置进行快速插入或删除元素
    • 采用动态存储分配,不会造成内存浪费和溢出
  • 缺点:

    • 容器遍历速度没有数组快;占用的空间比数组大(因为多出来指针域)

2. list构造函数

功能描述:创建list容器

函数原型注释
list lst;list采用模板类实现对象的默认构造形式
list<beg, end>;构造函数将【beg, end) 区间中的元素拷贝给本身
list(n,elem);构造函数将n个elem拷贝给本身
list(const list &lst);拷贝构造函数

示例

void printList(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>L1;

	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	//遍历容器
	printList(L1);

	//区间方式构造
	list<int>L2(L1.begin(), L1.end());
	printList(L2);

	//拷贝构造
	list<int>L3(L1);
	printList(L3);

	list<int>L4(8, 88);
	printList(L4);
}
----------------------------
10 20 30 40
10 20 30 40
10 20 30 40
88 88 88 88 88 88 88 88
请按任意键继续. . .

3. list赋值和交换

功能描述:给list容器进行赋值,以及交换list容器

函数原型

函数原型注释
assign(beg, end);将[beg,end)区间中的数据拷贝赋值给本身
assign(n, elem);将n个elem拷贝赋值给本身
list & operator = (const list &lst);重载等号操作符
swap(lst);将list与本身的元素互换

示例

void test01()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	printList(L1);

	list<int>L2;
	L2 = L1;
	printList(L2);

	list<int>L3;
	L3.assign(L2.begin(), L2.end());
	printList(L3);

	list<int>L4;
	L4.assign(8, 88);
	printList(L4);
}

//交换
void test02()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	list<int>L2;
	L2.assign(8, 88);

	cout << "交换前:" << endl;
	printList(L1);
	printList(L2);

	L1.swap(L2);
	cout << "交换后:" << endl;
	printList(L1);
	printList(L2);
}
-----------------
交换前:
10 20 30 40
88 88 88 88 88 88 88 88
交换后:
88 88 88 88 88 88 88 88
10 20 30 40
请按任意键继续. . .

4. list大小操作

功能描述:对list容器的大小进行操作

函数原型

函数原型注释
size();返回容器中元素的个数
empty();判断容器是否为空
resize(num);重新指定容器的长度为num,若容器变长,则以默认值重新填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(num, elem);重新指定容器的长度为num,若容器变长,则以elem值填充新位置,若容器变短,则末尾超出容器长度的元素被删除

示例

void test01()
{
	list<int>l1;
	l1.push_back(10);
	l1.push_back(20);
	l1.push_back(30);
	l1.push_back(40);
	printList(l1);

	//判断容器是否为空
	if (l1.empty())
	{
		cout << "l1为空" << endl;
	}
	else
	{
		cout << "l1不为空" << endl;
		cout << "l1中元素个数为:" << l1.size() << endl;
	}
	
	//重新指定大小
	l1.resize(10);
	printList(l1);

	l1.resize(2);
	printList(l1);
}
---------
10 20 30 40
l1不为空
l1中元素个数为:4
10 20 30 40 0 0 0 0 0 0
10 20
请按任意键继续. . .

5. list插入和删除

功能描述:对list容器进行数据的插入和删除

函数原型

函数原型注释
push_back(elem);在容器尾部加入一个元素
push_back( );删除容器中最后一个元素
push_front(elem);在容器开头插入一个元素
push_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值匹配的元素

示例

void test01()
{
	list<int>L;

	//尾插
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);

	//头插
	L.push_front(100);
	L.push_front(200);
	L.push_front(300);

	printList(L);

	//尾删
	L.pop_back();
	printList(L);	//300 200 100 10 20

	//头删
	L.pop_front();
	printList(L);	//200 100 10 20

	//insert插入
	L.insert(L.begin(), 88);
	printList(L);	//88 200 100 10 20
	

	list<int>::iterator it = L.begin();
	L.insert(++it, 8888);
	printList(L);	//88 8888 200 100 10 20

	//删除
	it = L.begin();
	L.erase(it);
	printList(L);	//8888 200 100 10 20

	//移除
	L.push_back(10000);
	L.push_back(10000);
	L.push_back(10000);
	printList(L);	//8888 200 100 10 20 10000 10000 10000
	L.remove(10000);
	printList(L);	//8888 200 100 10 20

	L.clear();
	printList(L);
}

6. list数据存取

功能描述:对list容器数据进行存取

函数原型

函数原型注释
front();返回第一个元素
back();返回最后一个元素

示例

void test01()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	//不可以用中括号和at()方式访问list容器中的元素、
	//原因是因为list本质是链表,不是用连续性空间存储数据,迭代器也不支持随机访问
	cout << "第一个元素是:" << L1.front() << endl;
	cout << "最后一个元素是:" << L1.back() << endl;
}

7. list反转和排序

功能描述:将容器中的元素反转,以及将容器中的数据进行排序

函数原型:

函数原型注释
reverse();反转排序
sort();链表排序

示例:

void printList(const list<int>&L) 
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

//提供sort重载函数
bool myCompare(int v1,int v2)
{
	//降序:就让第一个数>第二个数
	return v1 > v2;
}

void test01()
{
	list<int>L1;
	L1.push_back(20);
	L1.push_back(50);
	L1.push_back(40);
	L1.push_back(30);
	L1.push_back(220);
	L1.push_back(1);

	cout << "反转前:";
	printList(L1);

	//反转后
	cout << "反转后:";
	L1.reverse();
	printList(L1);

	//排序
	//不支持随机访问迭代器的容器,内部会支持对应的一些算法
	cout << "排序后:";
	L1.sort();	//默认升序
	printList(L1);
	cout << "降序:";
	L1.sort(myCompare);
	printList(L1);
}
----------------------
反转前:20 50 40 30 220 1
反转后:1 220 30 40 50 20
排序后:1 20 30 40 50 220
降序:220 50 40 30 20 1
请按任意键继续. . .

8. 排序案例

案例描述:将Person自定义数据类型进行排序,Person属性中有姓名,年龄,身高

排序规则:按照年龄进行升序,如果年龄相同则按照身高排序

示例:

class Person
{
public:
	Person(string name, int age, int height)
	{
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
	}
	string m_name;
	int m_age;
	int m_height;
};

//指定排序规则
bool myCompare(Person &p1,Person &p2)
{
	//年龄相同,按照身高进行降序
	if (p1.m_age == p2.m_age)
	{
		return p1.m_height > p2.m_height;
	}
	else
	{
		//按照年龄升序
		return p1.m_age < p2.m_age;
	}
}
void test01()
{
	list<Person> L;
	Person p1("楚子航", 22, 188);
	Person p2("夏弥", 21, 168);
	Person p3("凯撒", 24, 192);
	Person p4("诺诺", 23, 171);
	Person p5("绘梨衣", 19, 165);
	Person p6("路明非", 22, 183);

	//向容器中插入数据
	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	L.push_back(p6);

	cout << "排序前:" << endl;
	for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名:" << (*it).m_name << " "
			<< "\t年龄:" << (*it).m_age << " "
			<< "\t身高:" << (*it).m_height << endl;
	}

	cout << "排序后:" << endl;
	L.sort(myCompare);
	for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名:" << (*it).m_name << " "
			<< "\t年龄:" << (*it).m_age << " "
			<< "\t身高:" << (*it).m_height << endl;
	}
}
-----------------------
排序前:
姓名:楚子航    年龄:22        身高:188
姓名:夏弥      年龄:21        身高:168
姓名:凯撒      年龄:24        身高:192
姓名:诺诺      年龄:23        身高:171
姓名:绘梨衣    年龄:19        身高:165
姓名:路明非    年龄:22        身高:183
排序后:
姓名:绘梨衣    年龄:19        身高:165
姓名:夏弥      年龄:21        身高:168
姓名:楚子航    年龄:22        身高:188
姓名:路明非    年龄:22        身高:183
姓名:诺诺      年龄:23        身高:171
姓名:凯撒      年龄:24        身高:192
请按任意键继续. . .
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值