天津市网站建设_网站建设公司_VPS_seo优化
2025/12/31 14:08:40 网站建设 项目流程

主要针对 C++ 泛型编程STL 技术做详细讲解,探讨 C++ 更深层的应用。

一、模板

1、模板的概念

模板就是建立 通用的模具 ,大大提高 复用性

模板的特点

  • 模板不可以直接使用,它只是一个框架。

  • 模板的通用不是万能的。

模板的组成

  • template<> 开头,之后跟函数或者类。

  • <> 内为模板参数,一般使用 "class/typename",可以有多个参数,在调用模板的时候,可以在 <> 内添加具体的数据类型,即若未添加具体参数,则在调用的模板的时候是自动类型推导,而若添加了具体参数,就是指定类型推导。

  • template<class T> 这个 "T" 为一个通用数据类型,在使用函数模板的时候,会自动进行数据推导。

2、函数模板

  • C++ 另一种编程思想称为 泛型编程,主要利用的技术就是模板。

  • C++ 提供两种模板机制:函数模板类模板

函数模板语法

函数模板引用:

建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个 虚拟的类型 来代表。

语法

template<typename T>
函数声明或定义

解释

template --- 声明创建模板。

typename --- 表示其后面的符号是一种数据类型,可以用 class 代替。

T --- 通用的数据类型,名称可以替换,通常为大写字母。

实例

#include<iostream>
using namespace std;//交换函数
//交换整型
void swapInt(int& a, int& b) {int temp;temp = a;a = b;b = temp;
}
//交换浮点型
void swapDouble(double& a, double& b) {double temp;temp = a;a = b;b = temp;
}
//函数模板
//可以看到上述函数整体代码是相似的,只有数据类型不同,因此可以抽象成模板
template<typename T>	//声明一个模板,告诉编译器紧随其后的T不要报错,T是一个通用数据类型
void myswap(T& a, T& b) {T temp;temp = a;a = b;b = temp;
}void test01() {int a = 10;int b = 20;float c = 3.14;float d = 6.28;//使用函数模板进行交换//两种方式使用//1、自动类型推导myswap(a, b);//2、显示指定类型myswap<float>(c, d);cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;cout << "d = " << d << endl;
}int main() {test01();system("pause");return 0;
}

函数模板注意事项

注意实现:

  • 自动类型推导,必须推导出一致的数据类型 T,才可以使用。

  • 模板必须要确定出 T 的数据类型,才可以使用。

  • 只有紧跟在模板之后的函数才属于模板内容,被称为模板函数,在此之后的函数与模板没有关系

实例

#include<iostream>
using namespace std;//交换函数
//交换整型
void swapInt(int& a, int& b) {int temp;temp = a;a = b;b = temp;
}
//交换浮点型
void swapDouble(double& a, double& b) {double temp;temp = a;a = b;b = temp;
}
//函数模板
//可以看到上述函数整体代码是相似的,只有数据类型不同,因此可以抽象成模板
template<typename T>	//声明一个模板,告诉编译器紧随其后的T不要报错,T是一个通用数据类型
void myswap(T& a, T& b) {T temp;temp = a;a = b;b = temp;
}template<class t>
void func() {cout << "func 正在被调用" << endl;
}void test01() {int a = 10;int b = 20;float c = 3.14;float d = 6.28;//1、自动类型推导,必须推导出一致的数据类型T,才可以使用//myswap(a, c);		//错误,因为一个是int,一个是float//2、显示指定类型//func();		//错误,模板没有确定出具体的数据类型。
}int main1() {test01();system("pause");return 0;
}

函数模板案例

案例

#include<iostream>
using namespace std;template<class t>
void myswap3(t&a,t&b) {t temp;temp = a;a = b;b = temp;
}template<class T>
void mysort(T array[], int len) {for (int i = 0; i < len; i++) {int max = i;		//认定最大值的下标for (int j = i + 1; j < len; j++) {if (array[i] < array[j]) {max = j;}}if (max != i) {//交换max和i元素myswap3(array[max], array[i]);}}
}template<class T>
void printArray(T array[],int len) {cout <<"最大值为:"<< array[0] << endl;
}
void test03() {//测试char数组char Carray[] = "abcde";int len = sizeof(Carray) / sizeof(char);mysort(Carray, len);printArray(Carray, len);
}void test003() {//测试int数组int array[] = { 1,2,5,4,3,6,7,9 };int len = sizeof(array) / sizeof(int);mysort(array, len);printArray(array, len);
}int main() {//test03();test003();system("pause");return 0;
}

普通函数与函数模板的区别

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)。

  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换。

  • 如果利用显示指定类型的方式,可以发生隐式类型转换。

实例

#include<iostream>
using namespace std;//普通函数调用时可以发生自动类型转换(隐式类型转换)
int myadd(int a, int b) {return a + b;
}template<class T>
T myadd2(T a, T b) {return a + b;
}void test4() {int a = 10,  b = 20;	char c = 'c';			//a-97   c-99cout << myadd(a, c) << endl;//函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换//myadd2(a, c);			//报错,a和c不是同种类型//如果利用显示指定类型的方式,可以发生隐式类型转换myadd2<int>(a, c);		//正确,指定了T为int,即所有的实参都会被自动转换为int型。}int main4() {test4();system("pause");return 0;
}

普通函数与函数模板调用规则

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数。

  2. 可以通过空模板参数列表来强制调用函数模板。

  3. 函数模板也可以发生重载。

  4. 如果函数模板可以产生更好的匹配。优先调用函数模板。

  5. <> 内部为函数模板的参数,用来传入数据类型。

  6. 普通函数与函数模板最好不要同时出现。

实例

#include<iostream>
using namespace std;void myprint(int a, int b) {cout << "普通函数正在被调用" << endl;
}void myprint(int a, int b, int c) {cout << "普通函数重载正在被调用" << endl;
}template<class T>
void myprint(T a, T b) {cout << "函数模板正在被调用" << endl;
}template<class T>
void myprint(T a, T b, T c) {cout << "函数重载模板正在被调用" << endl;
}void test5() {int a = 10, b = 20;char c = 'c';//如果函数模板和普通函数都可以实现,优先调用普通函数myprint(a, b);		//	普通函数正在被调用//可以通过空模板参数列表来强制调用函数模板myprint<>(a, b);	//	函数模板正在被调用//函数模板也可以发生重载myprint(a, b, c);	//	普通函数重载正在被调用myprint<int>(a, b, c);	//函数重载模板正在被调用//如果函数模板可以产生更好的匹配。优先调用函数模板char c1 = 1, c2 = 2;myprint(c1, c2);	//	函数模板正在被调用:因为使用普通函数转会有强制类型转换,而使用模板更合适
}int main() {test5();system("pause");return 0;
}

模板的局限性

  • 模板的通用性并不是万能的

例如

template<class T>
void f(T a,T b){a = b;
}

在上述代码的赋值中,假如传入的参数是一个数组,就会无法实现。

再例如

template<class T>
void f(T a,T b){if(a>b){....}
}

在上述代码中,如果 T 的数据类型传入的是像 Person 这样的自定义数据类型,也无法正常运行。

因此 C++ 为了解决这些问题,提供模板的重载,可以为这些 特定的类型 提供 具体的模板

实例

#include<iostream>
using namespace std;class Person {
public:Person(string name, int age){this->age= age;this->name = name;}string name;int age;
};template<class T>
bool myCompare(T &a, T &b) {if (a == b) {return true;}else{return false;}
}//利用具体化Person的版本实现代码,具体化优先调用
template<>		//以template<>开头,不必设置<>内参数,对上述模板进行重载,意在假如传入的参数是					  Person数据类型的时候,优先调用具体化Person版本的重载函数
bool myCompare(Person& a, Person& b) {if (a.age == b.age && a.name == b.name) {return true;}else{return false;}
}void test06() {//测试普通数据类型的对比int a = 10, b = 20;bool ret = myCompare(a, b);if (ret) {cout << "a==b" << endl;}else{cout << "a!=b" << endl;}
}void test006() {//测试自定义数据类型的对比Person p1("Tom", 18), p2("Jerry", 20);bool ret = myCompare(p1, p2);		//在未出现第行代码的时候,会进行报错,因为无法判断自定义类型的判断标准if (ret) {cout << "p1==p2" << endl;}else {cout << "p1!=p2" << endl;}
}int main() {test06();system("pause");return 0;
}

3、类模板

类模板语法

类模板作用

  • 建立一个通用类,类中的成员 数据类型可以不具体指定,用一个 虚拟的类型 来代表。

语法

template<class T>
class

实例

#include<iostream>
using namespace std;template<class NameType,class AgeType>
class Person {
public:Person(NameType Name, AgeType age) {this->s_age = age;this->s_Name = Name;}void show() {cout << "Name:" << this->s_Name << " Age:" << this->s_age << endl;}NameType s_Name;AgeType s_age;
};void test1() {Person<string, int> p1("孙悟空", 999);p1.show();
}int main() {test1();system("pause");return 0;
}

类模板与函数模板的区别

区别

  • 函数模板中 template 之后跟的是函数,类模板之后跟的是类。

  • 类模板没有自动类型推导的使用方式。

  • 类模板在模板参数列表中可以有默认参数。

实例

#include<iostream>
using namespace std;template<class NameType, class AgeType=int>		//第二个为默认参数
class Person2 {
public:Person2(NameType Name, AgeType age) {this->s_age = age;this->s_Name = Name;}void show() {cout << "Name:" << this->s_Name << " Age:" << this->s_age << endl;}NameType s_Name;AgeType s_age;
};void test2() {Person2<string> p1("孙悟空", 999);p1.show();
}int main() {test2();system("pause");return 0;
}

类模板中成员函数创建时机

  • 普通类中的成员函数一开始就可以创建。

  • 类模板中的成员函数在调用时才能创建。

实例

#include<iostream>
using namespace std;class Person1 {
public:void showPerson1() {cout << "Person1 show" << endl;}
};class Person2 {
public:void showPerson2() {cout << "Person2 show" << endl;}
};template<class T>
class myclass {
public:T obj;void func1() {obj.showPerson1();}void func2() {obj.showPerson2();}};void test3() {myclass<Person1>m;m.func1();myclass<Person2>mm;mm.func2();
}int main() {test3();system("pause");return 0;
}

类模板对象做函数参数

目标 :类模板实例化的对象,向函数传参的方式。

一共有三种传入方式:

  1. 指定传入的类型 —— 直接显示成员的数据类型。

  2. 参数模板化 —— 将对象中的参数变为模板进行传递。

  3. 整个类模板化 —— 将这个对象类型模板化进行传递。

实例

#include<iostream>
using namespace std;template<class T1,class T2>
class Person4 {
public:Person4(T1 name, T2 age) {this->s_Name = name;this->s_age = age;}T1 s_Name;T2 s_age;
};//指定传入的类型——直接显示成员的数据类型
void myprint4(Person4<string, int>&p) {cout << "姓名:" << p.s_Name << " \t年龄:" << p.s_age << endl;
}
void test4() {Person4<string, int> p("孙悟空", 1000);myprint4(p);
}//参数模板化——将对象中的参数变为模板进行传递
template<class T1,class T2>
void myprint04(Person4<T1, T2>& p) {cout << "姓名:" << p.s_Name << " \t年龄:" << p.s_age << endl;cout << "T1的数据类型为:" << typeid(T1).name() << endl;cout << "T2的数据类型为:" << typeid(T2).name() << endl;
}
void test04() {Person4<string, int> p("猪八戒", 500);myprint04(p);
}//整个类模板化——将这个对象类型模板化进行传递
template<class T1>
void myprint004(T1& p) {cout << "姓名:" << p.s_Name << " \t年龄:" << p.s_age << endl;cout << "T1的数据类型为:" << typeid(T1).name() << endl;
}
void test004() {Person4<string, int> p("唐僧", 100);myprint004(p);
}int main() {test4();test04();test004();system("pause");return 0;
}

类模板与继承

当类模板碰到继承时,需要注意以下几点:

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型。

  • 如果不指定,编译器无法给子类分配内存。

  • 如果想要灵活指出父类中 T 的类型,子类也需变为类模板。

实例

#include<iostream>
using namespace std;template<class T>
class Base {
public:T m;
};//当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
class Son :public Base<int> {};//想要灵活指出父类中T的类型,子类也需变为类模板
template<class T1,class T2>
class Son1 :public Base<T2> {
public:Son1() {cout << "T1的数据类型为:" << typeid(T1).name() << endl;cout << "T2的数据类型为:" << typeid(T2).name() << endl;}T1 obj;
};void test5() {Son1<int, char> obj;
}int main() {test5();system("pause");return 0;
}

类模板成员函数类外实现

目标 :掌握类模板中的成员函数类外实现。

实例

#include<iostream>
using namespace std;template<class T1, class T2>
class Person6 {
public:Person6(T1 Name, T2 age);void show();T1 s_Name;T2 s_age;
};template<class T1,class T2>
Person6<T1, T2>::Person6(T1 Name, T2 age) {this->s_age = age;this->s_Name = Name;
}template<class T1, class T2>
void Person6<T1, T2>::show() {cout << "Name:" << this->s_Name << " Age:" << this->s_age << endl;
}void test6() {Person6<string, int>p("孙悟空",1000);p.show();
}int main() {test6();system("pause");return 0;
}

类模板的分文件编写

问题

  • 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到。

解决

  • 方法一:直接包含 .cpp 源文件。

  • 方法二:将声明和实现写到同一个文件中,并更改后缀名为 .hpp 文件,hpp 是约定俗称的,不是强制的。

实例

头文件 Person.hpp

#pragma once
#include<iostream>
using namespace std;template<class T1, class T2>
class Person7 {
public:Person7(T1 Name, T2 age);void show();T1 s_Name;T2 s_age;
};template<class T1, class T2>
Person7<T1, T2>::Person7(T1 Name, T2 age) {this->s_age = age;this->s_Name = Name;
}template<class T1, class T2>
void Person7<T1, T2>::show() {cout << "Name:" << this->s_Name << " Age:" << this->s_age << endl;
}

源文件Person.cpp

#include<iostream>
using namespace std;#include"Person.hpp"void test7() {Person7<string, int>p("孙悟空", 1000);p.show();
}int main() {test7();system("pause");return 0;
}

类模板与友元

全局函数类内实现—直接在类内声明友元即可。

全局函数类外实现—需要提前让编译器知道全局函数的存在。

4、模板理解

模板是 C++ 编程中的一个重要模式,它可以减少代码的重复,提高代码的复用性,在 C++ 中,模板分为自己创建的模板以及自带模板。

​当自己创建模板的时候,首先需要代码 template<class T>,并紧随其后写一个函数或者类,称为函数模板或者类模板,假如模板名称为 My,那么无论是函数模板还是类模板,在使用的时候,必须有 模板名尖括号 “<>”,其中尖括号内必须有指定数据类型,那么紧随其后传入的数据类型必须与指定的数据类型一致。

C++ 中也有语言自带的模板,例如容器 vector 就是一个类模板,在底层中是这样的。

template <class T>
class vector { }

​在使用的时候,vector<int> v,对应关系为 vector--template<int>--<class T>,模板名与 <参数类型> 是必不可少的。

二、STL 初识

1、STL 的诞生

  • 长久以来,软件界一直希望建立一种可重复利用的东西。

  • C++面向对象泛型编程 思想,目的就是 复用性的提升

  • 大多数情况下,数据结构和算法都未能有一套标准,导致被迫从事 大量重复工作

  • 为了建立数据结构和算法的一套标准,诞生了 STL

2、STL 基本概念

  • STL (Standard Template Library,标准模板库)。

  • STL 从广义上分为:容器 (container)算法 (algorithm) 迭代器 (iterator)

  • 容器算法 之间通过 迭代器 进行无缝衔接。

  • STL 几乎所有的代码都采用了模板类或者模板函数。

3、STL 六大组件

STL 大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  1. 容器 :各种数据结构,如 vector、list、deque、set、map 等,用来存放数据。

  2. 算法 :各种常用的算法,如 sort、find、copy、for_each 等。

  3. 迭代器 :扮演了容器与算法之间的胶合剂。

  4. 仿函数 :行为类似函数,可作为算法的某种策略。

  5. 适配器 :一种用来修饰容器或者仿函数或迭代器接口的东西。

  6. 空间配置器 :负责空间的配置与管理。

4、STL 中容器、算法、迭代器

容器 :置物之所也

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

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

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

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

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

通俗来讲,容器就是用来存放数据的一片空间,一般容器中的元素数据类型都是相同的,容器可以存放内置的数据类型,例如 int,float 等等,也可以存放自定义的数据类型,例如自己创建的一个 Person 类,使用方法为: vector<数据类型> v

算法 :问题之解法也

有限的步骤,解决逻辑或数学上的问题,这一门学科称之为算法。

算法分为: 质变算法非质变算法

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

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

迭代器 :容器和算法之间粘合剂

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

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

迭代器的使用非常类似于 指针,初学时候可以将其理解为指针。

迭代器种类:

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

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

5、容器算法迭代器初识

STL 中最常见的容器为 Vector,可以理解为数组。

vector 存放内置数据类型

容器:vector

算法:for_each(InputIterator first, InputIterator last, Function f)

  • first :表示要处理的范围的起始位置的迭代器。

  • last :表示要处理的范围的结束位置的迭代器(不包括这个位置的元素)。

  • f :表示要执行的操作,它是一个函数或函数对象,它接受范围内的元素作为参数,用于执行相应的操作。

  • for_each() 函数将会遍历指定范围内的所有元素,并依次调用 f 函数或函数对象,将每个元素作为参数传递给 f 进行处理。for_each() 并不会返回任何值,它只是对范围内的元素进行遍历和操作。

迭代器:vector<int>::iterator

实例

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>void Myprint(int val) {cout << val << endl;
}void test01() {vector<int> v;		//创建一个容器vv.push_back(10);	//使用尾插法将数据插入到容器v中v.push_back(20);v.push_back(30);v.push_back(40);//遍历方法//方法一:利用迭代器创建指针vector<int>::iterator itBegin = v.begin();		//vector<int>::iterator是一个指针型的数据类型,此处相当于创建一个指针指向容器的第一个元素,而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;}//方法三//利用算法迭代for_each(v.begin(), v.end(), Myprint);		
}int main() {test01();system("pause");return 0;
}

vector 中存放自定义数据类型

实例

#include<iostream>
using namespace std;
#include<vector>class Person {
public:Person(string name, int age) {this->s_Name = name;this->s_Age = age;}string s_Name;int s_Age;
};void test02() {vector<Person> v;Person p1("aaa", 10);Person p2("bbb", 20);Person p3("ccc", 30);Person p4("ddd", 40);Person p5("eee", 50);v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);v.push_back(p5);for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {cout << "姓名:"<< (*it).s_Name << " 年龄:" << (*it).s_Age << endl;}}int main() {test02();system("pause");return 0;
}

三、STL - 常见容器

1、String 容器

基本概念

本质

  • stringC++ 风格的字符串,而 String 本质上是一个类。

Stringchar* 的区别

  • char * 是一个指针。

  • string 是一个类,类内部封装了 char *,管理这个字符串,是一个 char * 型的容器。

特点

string 类内部添加了很多成员方法。

例如:查找 find,拷贝 copy,删除 delete,替换 replace,插入 insert

string 管理 char * 所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责。

string 构造函数

构造函数原型

  • string() //创建一个空的字符串 例如:string str

  • string (const char * s) //使用字符串 s 初始化。

  • string (const string & str) //使用一个 string 对象初始化另一个 string 对象。

  • string (int n,char c) //使用 n 个字符 c 初始化。

实例

#include<iostream>
using namespace std;/** 
string()							//创建一个空的字符串 例如:string  str
string (const char * s) 			//使用字符串s初始化
string (const string & str)			//使用一个string对象初始化另一个string对象
string (int n,char c)				//使用n个字符c初始化
*/void test01() {string s1;	const char* str = "HelloWorld";string s2(str);cout << "s2 = " << s2 << endl;string s3(s2);cout << "s3=" << s3 << endl;string s4(10, 'a');cout << "s4 =" << s4 << endl;}int main() {test01();system("pause");return 0;
}

string 赋值操作

函数原型

  • string& operator=(const char * ) //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<iostream>
using namespace std;/*
string& operator=(const char * )			//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 test02() {string str1;str1 = "HelloWorld";cout << "str1 = " << str1 << endl;string str2;str2 = str1;cout << "str2 = " << str2 << endl;string str3;str3 = 'a';cout << "str3 = " << str3 << endl;string str4;str4.assign("Hello C++!");cout << "str4 = " << str4 << endl;string str5;str5.assign("Hello C++!", 5);cout << "str5 = " << str5 << endl;string str6;str6.assign(str5);cout << "str6 = " << str6 << endl;string str7;str7.assign(10,'w');cout << "str7 = " << str7 << endl;
}int main() {test02();system("pause");return 0;
}

string 字符串拼接

  • 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 stirng& str)

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

实例

#include<iostream>
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 stirng& str)
-string& append(const string &s,int pos,int n)	//字符串s中从pos开始的n个字符连接到字符串结尾
*/void test03() {string str1 = "我";str1 += "爱玩游戏";cout << "str1 = " << str1 << endl;str1 += ':';cout << "str1 = " << str1 << endl;string str2 = "LOL DNF";str1 += str2;cout << "str1 = " << str1 << endl;string str3 = "I";str3.append(" love");cout << "str3 = " << str3 << endl;str3.append(" game ,abcde", 5);cout << "str3 = " << str3 << endl;str3.append(str2);cout << "str3 = " << str3 << endl;str3.append(str2, 0, 3);cout << "str3 = " << str3 << endl;
}int main() {test03();system("pause");return 0;
}

string 查找和替换

功能描述

  • 查找 :查找指定字符串是否存在。

  • 替换 :在指定的位置替换字符串。

函数原型

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

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

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

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

  • int rfind(const string& str,int pos=npos)const //查找 string 最后一次位置,从 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 最后一次出现的位置,从 pos 开始查找。

  • 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<iostream>
using namespace std;/*
-int find(const string& str,int pos=0)const				//查找`string`第一次出现的位置,从`pos`开始查找
-int find(const char* s,int pos=0)const					//查找`s`第一次出现的位置,从`pos`开始查找
-int find(const char* s,int pos=0,int n)const			//从`pos`位置查找`s`的前`n`个字符第一次位置
-int find(const char c,int pos=0)const					//查找`c`第一次出现的位置,从`pos`开始查找
-int rfind(const string& str,int pos=npos)const			//查找`string`最后一次位置,从`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`最后一次出现的位置,从`pos`开始查找
-string& replace(int pos,int n,const string& str)		//替换从`pos`开始`n`个字符为字符串`str`
-string& replace(int pos,int n,const char *s)			//替换从`pos`开始`n`个字符为字符串`s`
*/void mprint(int &pos) {if (pos == -1) {cout << "未找到字符串" << endl;}else{cout << "找到字符串,pos = " << pos << endl;}
}//查找
void test04() {//find:从左往右查找string str1 = "abcdefgde";int pos = str1.find("de");mprint(pos);//rfind:从右往左查找pos = str1.rfind("de");mprint(pos);
}//替换
void test004() {string str1 = "abcdefg";str1.replace(1, 3, "11111");		//意思为将字符串从1号下标开始到3号下标结束,替换成指定字符串,无论指定字符串是否长度比原先长度长cout << "str1=" << str1 << endl;
}int main() {test04();test004();system("pause");return 0;
}

string 字符串比较

比较方式

  • 字符串比较是按 ASCALL 码进行对比。

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

函数原型

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

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

实例 :

#include<iostream>
using namespace std;/*
-int compare(const string &s)const				//与字符串`s`比较
-int compare(const char *s)const				//与字符串`s`比较
*/void test05() {string str1 = "Hello";int rel = str1.compare("H");cout << rel << endl;
}int main() {test05();system("pause");return 0;
}

string 字符存取

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

  • char & at(int n) //通过 at 取字符。

实例

#include<iostream>
using namespace std;/*
-char & operator[] (int n)		//通过`[]`取字符
-char & at(int n)				//通过`at`取字符
*/void test06() {string str = "Hello";for (int i=0; i < str.size(); i++) {cout << str[i] << " ";}cout << endl;for (int i=0; i < str.size(); i++) {cout << str.at(i) << " ";}cout << endl;//修改单个字符str[0] = 'x';cout << "str=" << str << endl;str.at(1) = 'x';cout << "str=" << str << endl;
}int main() {test06();system("pause");return 0;
}

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<iostream>
using namespace std;/*
-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`个字符
*/void test07() {string str1 = "hello";str1.insert(1, "elel");cout << "str1 = " << str1 << endl;str1.erase(1, 4);cout << "str1 = " << str1 << endl;
}int main() {test07();system("pause");return 0;
}

string 子串

函数原型

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

实例

#include<iostream>
using namespace std;//string substr(int pos =0,int n = npos)const			//返回由`pos`开始的`n`个字符组成的字符串void test08() {string str = "李四@.com";cout << "strSub = " << str.substr(0, 4) << endl;
}void test008() {string str = "lisi@.com";int pos = str.find('@');cout << "strSub = " << str.substr(0, pos) << endl;
}int main() {test08();test008();system("pause");return 0;
}

2、vector 容器

基本概念

功能

  • vector 数据结构和数组非常相似,也称为单端数组。

区别

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

动态扩展

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

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

vector 构造函数

函数原型

  • vector <T> v //采用模板实现类实现,默认构造函数。

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

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

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

实例

#include<iostream>
using namespace std;
#include<vector>/*
-vector <T> v						//采用模板实现类实现,默认构造函数
-vector (v.begin(),v.end())			//将`v[begin(),end())`前闭后开区间中的元素拷贝给本身
-vector (n,elem)					//构造函数将`n`个`elem`拷贝给本身
-vector (const vector &vec)			//拷贝构造函数
*/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, 100);printVector(v3);//拷贝构造vector<int>v4(v3);printVector(v4);
}int main() {test01();system("pause");return 0;
}

vector 赋值操作

函数原型

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

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

  • assign(n,elem) //将 nelem 拷贝给本身。

实例

#include<iostream>
using namespace std;
#include"printVector.h"/*
-vector& operator=(const vector& vec)		//重载等号操作符
-assign(beg,end)							//将`[beg,end)`区间中的数据拷贝赋值给本身
-assign(n,elem)								//将`n`个`elem`拷贝给本身
*/void test02() {vector<int>v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}printVector(v1);vector<int>v2;v2 = v1;printVector(v2);vector<int>v3;v3.assign(v1.begin(), v1.end());printVector(v3);vector<int>v4;v4.assign(10, 100);printVector(v4);}int main() {test02();system("pause");return 0;
}

vector 容量和大小

函数原型

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

  • capacity() //容器的容量。

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

  • resize(int num) //重新指定容器的长度为 num,若容器变长,则以默认值填充新位置,如果容器变短则末尾超出容器长度的元素被删除。

  • resize(int num,elem) //重新指定容器的长度为 num,若容器变长,则以 elem 填充新位置,如果容器变短则末尾超出容器长度的元素被删除。

实例

#include<iostream>
using namespace std;
#include"printVector.h"/*
-empty()					//判断容器是否为空
-capacity()					//容器的容量
-size()						//返回容器中元素的个数
-resize(int num)			//重新指定容器的长度为`num`,若容器变长,则以默认值填充新位置,如果容器变短则末尾超出容器长度的元素被删除
-resize(int num,elem)		//重新指定容器的长度为`num`,若容器变长,则以`elem`填充新位置,如果容器变短则末尾超出容器长度的元素被删除
*/void test03() {vector<int> v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}printVector(v1);if (v1.empty()) {cout << "容器为空" << endl;}else{cout << "容器不为空" << endl;cout << "容器的容量为:" << v1.capacity() << endl;cout << "容器的大小为:" << v1.size() << endl;}v1.resize(15);			//重新指定容器长度printVector(v1);v1.resize(16, 2);		//重新指定容器长度,并将多余位置用指定数字填充,默认为0printVector(v1);v1.resize(5);			//重新指定容器长度,如果变小了,会将多余的元素删除printVector(v1);cout << "重新指定长度之后的大小为:" << v1.size() << endl;
}int main() {test03();system("pause");return 0;
}

vector 插入和删除

函数原型

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

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

  • 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) //删除迭代器从 startend 之间的元素。

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

实例

#include<iostream>
using namespace std;
#include"printVector.h"/*
-push_back(ele)										//尾部插入元素`ele`
-pop_back(ele)										//删除最后一个元素
-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 test04() {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(), 1000);printVector(v1);v1.insert(v1.begin(), 2, 1000);		//可以指定数目printVector(v1);//删除v1.erase(v1.begin(),v1.end()-2);printVector(v1);//清空v1.clear();printVector(v1);}int main() {test04();system("pause");return 0;
}

vector 数据存取

函数原型

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

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

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

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

实例

#include<iostream>
using namespace std;
#include"printVector.h"/*
-at(int idx)		//返回索引`idx`所指的数据
-operator[]			//返回索引`idx`所指的数据
-front()			//返回容器中第一个数据元素
-back()				//返回容器中最后一个数据元素
*/void test05() {vector<int>v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}for (int i = 0; i < v1.size(); i++) {cout << v1[i] << " ";}cout << endl;for (int i = 0; i < v1.size(); i++) {cout << v1.at(i) << " ";}cout << endl;//返回第一个元素cout << "容器中第一个元素为:" << v1.front() << endl;//返回最后一个元素cout << "容器中最后一个元素为:" << v1.back() << endl;
}int main() {test05();system("pause");return 0;
}

vector 容器互换

功能描述

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

函数原型

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

实例

#include<iostream>
using namespace std;
#include"printVector.h"/*
swap(vec)			//将`vec`与本身的元素互换
*/void test06() {vector<int >v1;v1.push_back(10);v1.push_back(20);cout << "互换之前v1 = " ;printVector(v1);vector<int>v2;v2.push_back(30);cout << "互换之前v2=";printVector(v2);v1.swap(v2);cout << "互换之后v1 = ";printVector(v1);cout << "互换之后v2=";printVector(v2);}int main() {test06();system("pause");return 0;
}

vector 预留空间

功能描述

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

函数原型

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

实例 :

#include<iostream>
using namespace std;
#include"printVector.h"/*
reserve(int len)			//容器中预留`len`个元素长度,预留位置不初始化,元素不可访问
*/void test07() {vector<int>v;v.reserve(100000);int num=0;	//统计动态开辟多少次int* p = NULL;for (int i = 0; i < 100000; i++) {v.push_back(i);if (p != &v[0]) {p = &v[0];num++;}}cout << "动态开辟了" << num << "次" << endl;
}int main() {test07();system("pause");return 0;
}

3、deque 容器

deque 容器基本概念

功能

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

dequevector 区别

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

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

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

deque 构造函数

  • vector 一样,如果有需要,可以使用const来限定容器是只读状态。

deque 赋值操作

  • vector 一样。

deque 大小操作

  • vector一样,区别在于,deque 没有容量的概念。

deque 插入和删除

函数原型

两端插入操作:

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

  • push_front(elem) //在容器头部添加一个数据。

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

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

指定位置操作:

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

  • insert(pos,n,elem) //在 pos 位置插入 nelem 元素的拷贝,无返回值。

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

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

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

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

实例

#include<iostream>
using namespace std;
#include"print.h"/*
两端插入操作:-push_back(elem)			//在容器尾部添加一个数据
-push_front(elem)			//在容器头部添加一个数据
-pop_back(elem)				//删除容器最后一个数据
-pop_back(elem)				//删除容器第一个数据指定位置操作:-insert(pos,elem)			//在`pos`位置插入一个`elem`元素的拷贝,返回新数据的位置
-insert(pos,n,elem)			//在`pos`位置插入`n`个`elem`元素的拷贝,无返回值
-insert(pos,begin,end)		//在`pos`位置插入`[beg,end]`区间的数据,无返回值
-clear()`					//清空容器内的所有数据
-erase(beg,end)				//删除`[beg,end)`区间的数据,返回下一个数据的位置
-erase(pos)					//删除`pos`位置的数据,返回下一个位置的数据
*/void test01() {deque<int>d;d.push_back(10);d.push_back(20);d.push_front(100);d.push_front(200);printDeque(d);//头删d.pop_front();printDeque(d);//尾删d.pop_back();printDeque(d);
}void test001() {deque<int>d;d.push_back(10);d.push_back(20);d.push_front(100);d.push_front(200);printDeque(d);//insert插入d.insert(d.begin(), 1000);printDeque(d);d.insert(d.begin(), 2, 10000);printDeque(d);//按照区间进行插入deque<int>d2;d2.push_back(1);d2.push_back(2);d2.push_back(3);d.insert(d.begin(), d2.begin(), d2.end());printDeque(d);
}void test0001() {deque<int>d;d.push_back(10);d.push_back(20);d.push_front(100);d.push_front(200);printDeque(d);//删除//d.erase(d.begin());deque<int>::iterator it = d.begin();it++;d.erase(it);printDeque(d);//按区间进行删除d.erase(d.begin(),d.end());		//=d.clear();printDeque(d);
}int main() {test01();test001();test0001();system("pause");return 0;
}

deque 数据存取

  • vector一样。

deque 排序

功能描述

  • 利用算法实现对 deque 容器进行排序。

算法

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

实例

#include<iostream>
using namespace std;
#include<algorithm>
#include"print.h"void test02() {deque<int>d;d.push_back(10);d.push_back(233);d.push_back(75);d.push_back(135);d.push_back(223);printDeque(d);sort(d.begin(), d.end());printDeque(d);
}int main() {test02();system("pause");return 0;
}

4、stack 容器

stack 基本概念

概念stack 是一种先进后出的数据结构,它只有一个出口。

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

栈中进入数据称为 —— 入栈 push

栈中弹出数据称为 —— 出栈 pop

stack 常用接口

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

构造函数

  • stack<T> stk //stack 采用模板类实现,stack 的默认构造形式。

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

赋值操作

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

数据存取

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

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

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

大小操作

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

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

实例

#include<iostream>
using namespace std;
#include<stack>/*
构造函数:-stack<T> stk				//`stack`采用模板类实现,`stack`的默认构造形式-stack(const stack &stk)	//拷贝构造函数赋值操作:-stack & operator=(const stack &stk)			//重载等号操作符数据存取:-push(elem)			//向栈顶添加元素-pop()				//从栈顶移除第一个元素-top()				//返回栈顶元素大小操作:-empty()			//判断堆栈是否为空-size()				//返回栈的大小
*/void test() {stack<int> s;s.push(10);s.push(20);s.push(30);s.push(40);s.pop();stack<int> s2;s2 = s;while (!s.empty()) {cout << "s栈顶元素为:" << s.top() << endl;cout << "s栈的大小为:" << s.size() << endl;s.pop();}while (!s2.empty()) {cout << "s2栈顶元素为:" << s2.top() << endl;cout << "s2栈的大小为:" << s2.size() << endl;s2.pop();}}int main() {test();system("pause");return 0;
}

5、queue 容器

queue 基本概念

概念 :queue 是一种 先进先出 的数据结果,有两个出口。

队列允许从一端新增元素,从另一端移除元素。

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

queue 常用接口

构造函数

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

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

赋值操作

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

数据存取

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

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

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

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

大小操作

  • empty() //判断队列是否为空。

  • size() //返回队列的大小。

实例

#include<iostream>
using namespace std;
#include<queue>/*
构造函数:-queue<T> que						//`queue`采用模板类实现,`queue`对象的默认构造形式-queue(const  queue  &que)			//拷贝构造函数赋值操作:-queue& operator=(const queue &que)			//重载等号操作符数据存取:-push(elem)			//往队尾添加元素-pop()				//从队头移除第一个元素-back()				//返回最后一个元素-front()			//返回第一个元素大小操作:-empty()			//判断队列是否为空-size()				//返回队列的大小
*/void test() {queue<int> q;q.push(10);q.push(20);q.push(30);q.push(40);queue<int> q2;q2 = q;while (!q.empty()) {cout << "队列第一个元素为: " << q.front() << endl;cout << "队列最后一个元素为:" << q.back() << endl;cout << "队列的大小为: " << q.size() << endl;q.pop();cout << endl;}}int main() {test();system("pause");return 0;
}

6、list 容器

list 基本概念

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

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

组成 :链表由一系列节点组成。

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

list 构造函数

函数原型

  • list<T> lst //list 采用模板类实现对象的默认构造形式。

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

  • list(n,elem) //构造函数将 nelem 拷贝给自身。

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

实例

#include<iostream>
using namespace std;
#include"printList.h"/*
-list<T> lst				//`list`采用模板类实现对象的默认构造形式
-list(beg,end)				//构造函数将`[beg,end]`区间中的元素拷贝给自身
-list(n,elem)				//构造函数将`n`个`elem`拷贝给自身
-list(const list &list)		//拷贝构造函数
*/void test01() {list<int> L;L.push_back(10);L.push_back(20);L.push_back(30);L.push_back(40);printList(L);list<int>L2(L.begin(),L.end());printList(L2);list<int>L3(L2);printList(L3);list<int>L4(4,100);printList(L4);}int main() {test01();system("pause");return 0;
}

list 赋值和交换

函数原型

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

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

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

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

实例

#include<iostream>
using namespace std;
#include"printList.h"/*
-assign(beg,end)						//将`[beg,end]`区间中的数据拷贝赋值给本身
-assign(n,elem)							//将`n`个`elem`拷贝赋值给本身
-list& operator=(const list &lst)		//重载等号操作符
-swap(lst)								//将`lst`与本身的元素互换
*/void test02() {list<int> L;L.push_back(10);L.push_back(20);L.push_back(30);L.push_back(40);printList(L);list<int>L2;L2.assign(L.begin(), L.end());printList(L2);list<int>L3;L3.swap(L2);printList(L3);printList(L2);}int main() {test02();system("pause");return 0;
}

list 大小操作

函数原型

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

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

  • resize(int num) //重新指定容器的长度为 num,若容器变长,则以默认值填充新位置,如果容器变短则末尾超出容器长度的元素被删除。

  • resize(int num,elem) //重新指定容器的长度为 num,若容器变长,则以 elem 填充新位置,如果容器变短则末尾超出容器长度的元素被删除。

list 插入和删除

函数原型

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

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

  • push_front(ele) //头部插入元素 ele

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

  • insert(const_iterator pos,ele) //迭代器指向位置 pos 插入元素 ele,返回新数据的位置。

  • insert(const_iterator pos,int count,ele) //迭代器指向位置 pos 插入 count 个元素 ele,无返回值。

  • insert(pos,beg,end) //迭代器指向位置 pos 插入 [beg,end] 区间中的元素,无返回值。

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

  • erase(beg,end) //删除迭代器从 begend 之间的元素,返回下一个数据的位置。

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

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

7、set/multiset 容器

基本概念

简介

  • 所有元素都会在插入时自动被排序。

本质

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

setmultiset 区别

  • set 不允许容器中有重复的元素。

  • multiset 允许容器中有重复的元素。

8、map/multimap 容器

基本概念

简介

  • map 中所有元素都是 pair(队组),即成对出现的数据。

  • pair 中第一个元素为 key(键值),起到索引作用,第二个元素为 value(实值)。

  • 所有元素都会根据元素的键值自动排序。

本质

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

优点

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

mapmultimap 区别

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

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

构造结构

  • 创建容器:map<数据类型,数据类型> m;

  • 插入数据:m.insert(pair<int,int>(1,10))

四、STL - 函数对象

1、函数对象

概念

概念

  • 重载 函数调用操作符 的类,其对象称为 函数对象
  • 函数对象 使用重载的 () 时,行为类似函数调用,称为 仿函数

本质

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

函数对象使用

特点

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

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

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

2、内建函数对象

概念

  • STL 内建了一些函数对象。

分类

  • 算数仿函数

  • 关系仿函数

  • 逻辑仿函数

用法

  • 这些仿函数所产生的对象,用法和一般函数完全相同。

  • 使用内建函数对象,需要引入头文件 #include<functional>

3、函数对象意义

​在使用算法的时候,由于普通函数无法作为参数运用到算法的参数列表中,因此,诞生了函数对象,通过类内对运算符的重载,实现相应的功能,此时由该类创建的对象不仅拥有函数的功能,同时也可以作为参数运用到算法中,其优点还有更多,例如函数对象拥有普通函数所不拥有的状态等等。

五、STL - 常用算法

概述

  • 算法主要是由头文件 <algorithm><functional><numeric> 组成。

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

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

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

1、常用遍历算法

  • for_each()for_each(起始迭代器,结束迭代器,函数/函数对象)

  • transform :搬运容器到另一个容器中 transform(原容器起始迭代器,原容器结束迭代器,目标容器起始迭代器,函数/函数对象),目标容器需要提前开辟空间,targert_v.resize(v.size())

2、常用查找算法

  • find() :查找指定元素,返回值类型为迭代器 find(iterator beg,iterator end,value)

  • find_if() :按条件查找元素,返回值类型为迭代器 find(iterator beg,iterator end,_Pred)_Pred 为谓词。

  • adjacent_find() :查找相邻重复元素 adjacent_find(iterator beg,iterator end)

  • find() :查找指定元素是否存在,返回值类型为bool binary_search(iterator beg,iterator end,value),必须为有序序列。

  • count() :统计元素出现次数 count(iterator beg,iterator end,value)

  • count_if() :按条件统计元素出现次数 count_if(iterator beg,iterator end,_Pred)

六、STL 总结

STL 中,包括三个重要组成部分:容器、迭代器、算法

  • 容器 :主要功能就是用于存放各种类型的数据,包括类,容器的种类有很多,分别拥有不同的功能,依据需要选择不同的容器来进行数据的存放,容器主要包括:String、vector、deque、stack、queue、list、set/multiset、map/multiset

    • 首先需要创建一个容器:容器类型<数据类型>容器名,例如 vector<int> v
    • 其次需要进行数据的存入:容器名.push_back(),需要注意的是,括号里面的数据类型需要与创建容器时所设的数据类型一致。
  • 迭代器 :当拥有一个容器的时候,如何获取容器内每个数据,与获取数组数据用到指针一样,在容器内部拥有属于自己可以直接使用的”指针“,即迭代器,迭代器充当指针用来依次读取容器内每一个数据的位置。

    • 容器名<数据类型>::iterator,它是一个数据类型,用于声明一个指针,此时这个指针就可以自由移动,可以使用 auto 关键字进行自动推导数据类型。
    • 容器有内置的获取第一个元素位置的方法 v.begin(),同理最后一个元素位置为 v.end()
    • 使用迭代器可以遍历容器内的每一个元素。
  • 算法

  • 函数对象 :分为自定义数据类型以及内建数据类型。

    • 内建数据类型是自带的函数对象,可以进行直接使用而不需要进行自己定义。
    • 自定义是由自己创建的函数对象,主要用作实现不同的功能。
    • 方法 :在一个类的内部进行对括号的重载 operator ()(参数列表),在重载的时候,如果参数列表中只有一个元素称为一元谓词,两个称为二元谓词,在重载之后,由于是在类内重载,因此在算法使用的时候,有的算法需要传入的是函数对象,此时需要将谓词转化为函数对象,即使用类创建一个匿名对象。
    • 注意 :使用函数对象的方法是,创建一个类,在这个类的内部重载运算符,以达到某种目的,由这种类所生成的对象称为函数对象,其主要用于在算法中作为参数以实现某种目的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询