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,可以理解为数组
| 容器 | 算法 | 迭代器 |
|---|---|---|
| vector | for_each | vector::iterator |
示例:
#include
#include //标准算法头文件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 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*,解引用后是Personfor (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 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类型的数据容器 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转化成了stringconst 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 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 void test01()
{string str1 = "hututugaagag";int pos1 = str1.find("hu");if (pos1 == -1)cout << "未找到字符串" << endl;elsecout << "字符串第一次出现的位置是:" << 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个字符替换为1111str1.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 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;elsecout << "str1 << endl;}
7. string 字符存取
string中单个字符串存取方式有两种
| 函数 | 注释 |
|---|---|
| char& operator[](int n); | 通过[]方式取字符 |
| char& art(int n); | 通过at方式获取字符 |
示例:
#include 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=aellostr1.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 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 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 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
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);//assignvector<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 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(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 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 //输入参数 const限定只读
void printDeque(const deque<int> &d)
{//获取迭代器deque::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 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 30cout << "第一个元素为:" << d.front() << endl;cout << "最后一个元素为:" << d.back() << endl;
}
7. deque排序
功能描述:利用算法实现对deque容器进行排序
算法:
sort(iterator beg,iterator end); //对beg和end区间元素进行排序
示例:
#include //标准算法头文件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) 区间中的元素拷贝给本身 |
| 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 20list<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 10000L.remove(10000);printList(L); //8888 200 100 10 20L.clear();printList(L);
}
6. list数据存取
功能描述:对list容器数据进行存取
函数原型:
| 函数原型 | 注释 |
|---|---|
| front(); | 返回第一个元素 |
| back(); | 返回最后一个元素 |
示例:
void test01()
{listL1;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
请按任意键继续. . .
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
