1. 内存分区模型
1.1 模型
- 运行前
- 代码区
- 只读
- 共享
- 全局区
- 运行后
- 栈区
- 堆区
- 利用new关键字,可以将数据开辟到堆区,默认局参在栈区
- 例:int * p = new int(10);(指针接受堆区的地址) test
1.2 new操作符
- new返回的是该数据类型的指针
- float * p = new float (2.1); int * arr = new int [10];
- delete p ; (释放p的内存) delete[] arr ;
2. 引用
2.1 引用的基本引用
数据类型 &别名 = 原名
- 引用必须初始化
- 引用后不可再次更改
2.2 引用作函数参数
void test1 (int &a , int &b){};//a,b分别为实参a,b名字相同的引用别名
void test2 (int *a , int *b){};
int main(){
int a,b;
test1(a,b); //引用传递
test2(&a,&b);//地址传递
}2.3 引用作函数返回值
- 不可返回局部变量的引用
int& test01(){
int a = 10;
return a;
}
int mian(){
int &ref = tset01();//错误
}
//操作系统只会做一次保留- 函数调用可作为左值
int& test02(){
static int a = 10;//全局变量,程序结束后才释放
return a;
}
int mian(){
int &ref = tset02();//正确
print//10
test02()=1000;
print//1000
}
//操作系统只会做一次保留- 引用的本质
- 常量指针
int a = 10;
int& ref = a; //即int* const ref = &a;2.4 常量引用
- 防止调用的函数修改形参!
- 通常修饰形参
int& ref = 10;//错误
const int& ref = 10;//正确,加入const后,编译器将其修改为
//int emp=10;const int& ref=temp;
3. 函数提高
3.1 函数默认参数
int func1(int a,int b =2,int c=3){}//调用func1时可不加b,c
//1,某位置已有默认参数,则这个位置后都要有默认值
//2,如果函数声明有默认参数,函数实现就不能有默认参数3.2 函数占位参数
void func(int a,int){}
3.3 函数重载
- 同一作用域下
- 函数名称相同
- 函数参数类型不同,个数不同,顺序不同
void func(){}
void func(int a){}- 注意事项(15课)
- 引用作为重载的条件
- 函数重载作为默认参数
4 .类和对象
4.1 封装
class 类
{
public:
//属性
//行为
private:
}- 类中的属性和行为一般称为成员
- 属性又称:成员属性,成员变量
- 行为又称:成员函数,成员方法
4.1.1 访问权限
- 公共权限: public, 类外可访问
- 保护权限: protected,类外不可访问 ,儿子可以访问父亲中的保护内容
- 私有权限: private, 类外不可访问, 儿子不可以访问父亲的私有内容
4.1.2 class 与 struct 区别
4.1.3 封装实例
#include<iostream>
#include<string.h>
using namespace std;
class Cube
{
public:
int get_L() {
return m_L;
}
void set_L(int a) {
m_L = a;
}
int get_W() {
return m_W;
}
void set_W(int a) {
m_W = a;
}
int get_H() {
return m_H;
}
void set_H(int a) {
m_H = a;
}
int calculateS() {
return 2 * m_L + 2 * m_W + 2 * m_H;
}
int calculateV() {
return m_H * m_L * m_W;
}
//利用成员函数判断是否相等
bool isSame(Cube c1,Cube c2) {
if (c1.m_H == c2.m_H && c1.m_L == c2.m_L && c1.m_W == c2.m_W) {
cout << "ture" << endl;
}
else
cout << "false" << endl;
return 0;
}
private:
int m_L;
int m_W;
int m_H;
};
int main() {
class Cube c1;
c1.set_L(10);
c1.set_W(20);
c1.set_H(30);
cout << "cube长度为" << c1.get_L() << endl;
cout << "cube面积为" << c1.calculateS() << endl;
cout << "cube体积为" << c1.calculateV() << endl;
class Cube c2;
c2.set_L(10);
c2.set_W(20);
c2.set_H(33);
c1.isSame(c1, c2);
}4.2 对象特征
4.2.1 构造函数
person()
{普通构造函数}
person(const person &p)
{age=p.age;}//拷贝构造函数-
分类
- 按参数:有参构造与无参(默认)构造
- 按类型:普通构造与拷贝构造
-
调用
- 括号法:
person p1;person p2(10);//有参构造函数person p3(p2);//拷贝构造函数
- 显示法:
person p1;person p2 = person(10);//有参构造person p3 = person p2;//拷贝构造
- 隐式转换法:
person p4 = 10;//相当于person p4 = person(10);//有参构造person p5 = p4;//拷贝构造
拷贝函数构造时机
- 使用一个已经创建的对象初始化一个新对象(省劲)
- 值传递的方式给函数参数传值(系统也干了)
- 值方式返回局部对象(如果调用函数返回值式p1) 深拷贝与浅拷贝
- 深:在堆区重新申请空间,进行拷贝操作(自己定义拷贝构造new解决)
- 浅:简单的复制拷贝操作
- 括号法:
4.2.2 析构函数
~person()
{
//析构函数
}4.2.3 初始化列表
...
person (int a,int b,int c):m_A,m_B,m_C
{
}
...
int main(){
person p (1,2,3);
}4.2.4 类对象作为类成员
#include<iostream>
#include<string>
using namespace std;
class Phone
{
public:
Phone(string pName) {
m_PName = pName;
}
string m_PName;
};
class Person
{
public:
string m_Name;
Phone m_Phone;
Person(string name, string pname) :m_Name(name),m_Phone(pname)
{
}
};
void test01() {
Person p ("段鑫", "iPhone13min");
cout << p.m_Name << "拥有" << p.m_Phone.m_PName << endl;
}
int main() {
test01();
system("pause");
}
4.2.5 静态成员
- 类内声明,类外初始化
class person
{
static int m_A;
}
int person::m_A = 100;//1,用类名访问cout<<perosn::m_A<<endl;2,通过对象访问4.2.6 静态成员函数
4.2.7 类外创建成员函数
语法: “返回类型 类名 :: 函数名(){};
GoodGay::GoodGay()//38课
{
buding = new Building;
}
void GoodGay::visit01()//调用函数
{
...
}4.3 对象模型和this指针
4.3.1 成员变量与成员函数分开储存
4.3.2 this 指针的使用
class person //1.区分形参与成员变量同名的情况
{
person& personAddPerson(person p)
{
this->age += p.age;
return *this; //在类的非静态成员函数中返回对象本身
}
}
p2.personAddPerson(p1).personAddPerson(p1);//链式编程4.3.3 空指针访问成员函数
class person
{
public:
void showPerson() const
// const person * const this
//在成员函数后面加const,修饰的式this指向,让其不被修改
{
m_A = 100;//报错
this->m_B = 100;
}
int m_A;
mutable int m_B;//特殊变量,即使在常函数中也可修改这个值
}
void test(){
const person p;
p.func();//报错,常对象只能调用常函数
}4.4 友元
4.4.1 全局函数作友元
class Building
{
friend void goodguy(Building* b);//全局函数作友元
friend class goodGuy;//4.4.2类作友元
friend void GoodGay::visit();//4.4.3成员函数作友元
public:
{
...
}
private:
...
}4.4.2 类作友元
4.3.3 成员函数作友元
4.5 运算符重载
- 对已有的运算符重新进行定义,赋予其另一种功能,以应对不同的数据类型
5.4.1 加法运算符重载
class Person
{
public:
/*Person operator+(Person& p)
{
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}*/
int m_A;
int m_B;
};
Person operator+(Person& p1,Person& p2)
{
Person temp;
temp.m_A = p2.m_A + p1.m_A;
temp.m_B = p2.m_B + p1.m_B;
return temp;
}
void test01() {
Person p1;
p1.m_A = 10;
p1.m_B = 10;
Person p2;
p2.m_A = 10;
p2.m_B = 10;
Person p3 = p1 + p2;
cout << p3.m_A << p3.m_B << endl;
}
int main() {
test01();
system("pause");
}5.4.2 左移运算符重载
ostream& operator << (osteam& out,Person& p){//本质operator<<(cout,p)
out << p.m_A << p.m_B;
return out;//可以使之再次使用
}5.4.3 递增运算符重载
MyInteger& operator++()//&为保证操作数一直正确
{
m_Num++;
return *this;//返回自身
}
//MyIntrger为自定义整型
//重载后置++运算符
MyInteger operator++(int)//int代表占位参数,可用于区分前置和后置递增
{
//先记录结果
MyInteger temp= *this;
//后递增
m_Num++;
//最后返回记录的结果
return temp;
5.4.4 赋值运算符重载
...
person(int age)
{
//将年龄数据开辟到堆区
m_Age = new int(age);
}
person& operator=(person &p)
{
//m_Age = p.m_Age;
//编译器提供的式浅拷贝
if(m_Age!=Null){
delete m_Age;
m_Age=null;
}
m_Age = new int(*p.m_Age);
return *this;
}5.4.5 关系运算符重载
bool operator==(person &p)
{
if(this->m_Age == p.m_Age && this->m_Name == p.m_Name){
return true;
}
return false;
}5.4.6 函数调用运算符重载
- 又称仿函数
4.6 继承
- 减少代码重复量
4.6.1 继承的基本语法
class A : public B;- A类称为子类(派生类
- B类称为父类(基类
//公共页面
class BasePage
{
public:
void header() {
cout << "header" << endl;
}
void footer() {
cout << "footer" << endl;
}
void left() {
cout << "left" << endl;
}
};
class Java :public BasePage
{
public:
void content() {
cout << "this is Java" << endl;
}
};
class Python :public BasePage
{
public:
void content() {
cout << "this is Python" << endl;
}
};
class Cpp :public BasePage
{
public:
void content() {
cout << "this is c++" << endl;
}
};
void test01() {
//Java
cout << "Java如下: " << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "--------------------" << endl;
//Python
cout << "Python如下: " << endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
cout << "--------------------" << endl;
//c++
cout << "C++如下: " << endl;
Cpp c;
c.header();
c.footer();
c.left();
c.content();
cout << "--------------------" << endl;
}
int main() {
test01();
}4.6.2 继承方式
- 公有继承:public
- 保护继承:protected
- 私有继承:private
4.6.3 继承中的对象模型
- vs开发人员命令工具
4.6.4 继承中的构造和析构顺序
- 先构造夫类后构造子类
- 先析构子类在析构父类
4.6.5 继承中同名成员处理
- 优先访问子类同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类和父类拥有同名的成员函数,子类会隐藏父类中的成员函数,同样需要加作用域
class Base
{
public:
int m_A;
Base() {
m_A = 100;
}
void func() {
cout << "base-func调用" << endl;
}
void func(int) {
cout << "bas-func(int)调用"<<endl;
}
};
class son : public Base {
public:
int m_A;
son() {
m_A = 200;
}
void func() {
cout << "son-func调用" << endl;
}
};
void test01() {
son s;
cout << s.m_A << endl;
cout << s.Base::m_A << endl;
s.func();
s.Base::func();
s.Base::func(10);//加作用域
}
int main() {
test01();
}4.6.6 继承中静态同名成员处理
class Base
{
public:
static int m_A;
Base() {
m_A = 100;
}
static void func() {
cout << "base-func调用" << endl;
}
static void func(int) {
cout << "bas-func(int)调用"<<endl;
}
};
int Base::m_A = 100;
class Son : public Base {
public:
static int m_A;
Son() {
m_A = 200;
}
static void func() {
cout << "son-func调用" << endl;
}
};
int Son::m_A = 200;
void test01() {
Son s;
cout << s.m_A << endl;
cout << s.Base::m_A << endl;
//通过类名访问
cout << Son::m_A << endl;
cout << Son::Base::m_A << endl;//
s.func();
s.Base::func();
s.Base::func(10);
//通过 类名访问
Son::func();
Son::Base::func();
Son::Base::func(10);//
}
int main() {
test01();
}4.6.7多继承语法
4.6.8 菱形继承
4.7 多态
4.7.1 多态的基本概念
- 静态多态:函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态:派生类和虚函数实现运行时多态
- 区别:编译阶段确定函数地址和运行阶段确定函数地址
父类指针指向子类对象
class Animal
{
public:
virtual void speak() {
//virtual关键字,变为虚函数,在编译器编译的时候不能确定函数调用了
cout << "动物在说话" << endl;
}
};
class Cat :public Animal
{
public:
void speak() {
cout << "小猫在说话" << endl;
}
};
void doSpeak(Animal& animal) {
animal.speak();
}//多态满足条件:
//有继承关系,子类重写父类中的函数
//多态使用:
//父类指针或引用指向子类对象
void test01() {
Cat cat;
doSpeak(cat);
}
int main() {
test01();
}
//重写:函数返回值 函数名 函数列表 完全一致称为重写4.7.2 多态案例一:计算器类
//class Calculator
//{
//public:
// int m_Num1;
// int m_Num2;
//
// int getResult(string opr) {
// if (opr == "+") {
// return m_Num1 + m_Num2;
// }
// if (opr == "-") {
// return m_Num1 - m_Num2;
// }
// }
//
//};
class AbstractCalculator//抽象类计算器
{
public:
int m_Num1;
int m_Num2;
virtual int getResult() {
return 0;
}
};
class addCalculator :public AbstractCalculator//具体计算器
{
public:
int getResult() {
return m_Num1 + m_Num2;
}
};
class subCalculator :public AbstractCalculator//具体计算器
{
public:
int getResult() {
return m_Num1 - m_Num2;
}
};
//void test() {
// Calculator c;
// c.m_Num1 = 7;
// c.m_Num2 = 4;
// cout <<"+为"<< c.getResult("+") << endl;
// cout << "-为" << c.getResult("-") << endl;
//}
void test01() {
AbstractCalculator * abc = new addCalculator;
abc->m_Num1 = 7;
abc->m_Num2 = 4;
cout << "+为" << abc->getResult() << endl;
delete abc;
}
void test02() {
AbstractCalculator* abc = new subCalculator;
abc->m_Num1 = 7;
abc->m_Num2 = 4;
cout << "-为" << abc->getResult() << endl;
delete abc;
}
int main() {
/*test();*/
test01();
test02();
}4.7.3 纯虚函数和抽象类
class Base
{
public:
virtual void func() = 0;//纯虚函数:只要有一个,这个类称为抽象类
//抽象类特点
//1,无法实例化对象
//1,抽象类的子类必须重写父类中的纯虚函数,否则也称为抽象类
};
class Son :public Base
{
public:
virtual void func() {
cout << "func调用" << endl;
}
};
void test01() {
/*Son s;*///子类必须重写父类中的纯虚函数,否则无法实例化对象
Base* base = new Son;//父类指针指向子类对象
base->func();
}
int main() {
test01();
}4.7.4 多态案例二:制作饮品
class AbstractDrinking
{
public:
virtual void Boil() = 0;
virtual void Brew() = 0;
virtual void PourInCup() = 0;
virtual void PutSomeThing() = 0;
void makeDrink() {
Boil();
Brew();
PourInCup();
PutSomeThing();
}
};
class Coffe :public AbstractDrinking
{
public:
virtual void Boil() {
cout << "农夫山泉" << endl;
};
virtual void Brew() {
cout << "冲泡咖啡" << endl;
};
virtual void PourInCup() {
cout << "倒入杯中" << endl;
};
virtual void PutSomeThing() {
cout << "加入咖啡和牛奶" << endl;
};
};
class Tea :public AbstractDrinking
{
public:
virtual void Boil() {
cout << "怡宝" << endl;
};
virtual void Brew() {
cout << "冲泡茶叶" << endl;
};
virtual void PourInCup() {
cout << "倒入杯中" << endl;
};
virtual void PutSomeThing() {
cout << "加入柠檬和枸杞" << endl;
};
};
void doWork(AbstractDrinking* abs)//AbstractDrinking * abs= new Coffe
{
abs->makeDrink();
delete abs;
}
void test01() {
doWork(new Coffe);
}
int main() {
test01();
}4.7.5 虚析构和纯虚析构
-
父类的指针在析构时候,不会调用子类的析构函数,导致子类如果又堆区属性,出现内存泄漏
-
虚析构语法:析构函数前加virtual “virtual ~Animal(){}
-
纯虚析构语法:析构函数前加virtual =0;后加具体代码实现
virtual ~Animal() = 0;Animal::~Animal(){}“
5. 文件操作
- ofstream:写操作
- ifstream:读操作
- fstream:读写操作
5.1 文本文件
写文件
- 包含头文件:include< fstream >//不然会出现:无法声明不完整的对象
- 创建流对象:ofstream ofs;
- 打开文件:ofs.open(“文件路径;打开方式”);(ios::out)
- 写数据:ofs <<“数据”;
- 关闭文件:ofs.close();
- 打开方式:。。。
读文件
- 包含头文件
- 创建流对象:ifstream ifs;
- 打开文件,并判断是否打开成功:ifs.open(“test.txt”,ios::in);
- if(!ifs.is_open()){};
- 读数据
char buf[1024]={0};
while (ifs>>buf)
{
cout<<buf<<endl;
}char buf[1024]={0};
while (ifs.getline(buf,sizeof(buf)))
{
cout<<buf<<endl;
}string buf;
while (getline(ifs,buf))
{
cout<<buf<<endl;
}5.1.1 删除文件
ofstream ofs("文件名",ios::trunc);
5.2 二进制文件
打开方式:ios::binary
5.2.1 写文件
``ostream& write(const char*) buffer,int len);``
5.2.2 读文件
``istream& read(char *buffer,int len);``
6. 模板
6.1 基本概念
- c++的另一种编程思想称为泛型编程,主要利用的技术为模板
- c++提供两种模板机制:函数模板和类模板;
6.2 函数模板
6.2.1 函数模板的语法
template<typename T>//typename=class
函数声明或定义template<typename T>
void mySwap(T& a, T& b) {//(模板必须确定出T的数据类型才可使用)
T temp = a;
a = b;
b = temp;
}
int main() {
int a = 2;
int b = 7;
//1,自动类型推导(必须推导出一致的数据类型T才可使用)
mySwap(a, b);
//2,显示指定类型
mySwap<int>(a, b);
cout << a << b << endl;
}6.2.2 普通函数和函数模板的区别
- 普通函数调用时可以发送自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,也可以发生隐式类型转换
6.2.3 普通函数和函数模板的调用规则
- 如果函数模板和普通函数都可以实现,优先调用普通函数
- 如果函数模板可以产生更好的匹配优先调用函数模板
- 函数模板也可以发生重载
- 可以通过空模板参数列表来调用函数模板//myPrint<>(a,b);
6.3 类模板
6.3.1 模板的局限性
6.3.2 类模板与函数模板区别
- 类模板没有字段类型推导的使用方法
- 类模板在模板参数列表中可以用有默认参数
template<class NameType,class AgeType>
//template<class NameType,class AgeType=int>
class Person
{
public:
Person(NameType name,AgeType age)
{
this->m_Name=name;
this->m_Age=age;
}
NameType m_Name;
AgeType m_Age;
void test(){
//Person p("宋上",12);1,错误,无法用自动类型推导
Person<string,int>p("宋上",12);
//Person<string>p("宋上",12);
//2,类模板在模板参数列表中可以用有默认参数
}6.3.3 类模板中成员函数创建时机
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才创建
6.3.4 类模板对象作函数参数
template<class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age)
{
this->m_Name=name;
this->m_Age=age;
}
void showPerson(){
cout<< <<endl;
}
NameType m_Name;
AgeType m_Age;
}
//1,指定传入类型
void printPerson1(Person<string,int>&p){
p.showPerson();
}
void west01(){
Person<string,int>p("孙武看",200);
ptintPerson1(p);
}
//2.参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p){
p.showPerson();
}
void west02(){
Person<string,int>p("孙武看",200);
ptintPerson2(p);
//3.整个类模板化
template<class T>
void printPerson3(T &p){
p.showPerson();
}
void test03(){
Person<string,int>p("唐僧",40);
}
6.3.5 类模板与继承
template<class T>
class Base
{
T m;
}
class Son:public Base<int>//必须要知道父类中的T类型才能继承
{
}
template<class T1,class T2>
class Son2:public Base<T2>
//如果想灵活指定父类中T的类型,子类也需要变类模板
{
T1 obj;
}
void test02(){
Son2<int,char>S2;
}6.3.4 类模板成员函数类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson()
{
}6.3.5 类模板分文件编写
6.3.6 类模板与友元
- 全局函数类内实现-直接在类内声明友元即可
- 全局函数类外实现-需要提前让编译器知道全局函数的存在
6.3.7 类模板案例
7. STL - 常见容器
- Standard Template Library,标准模板库
- 广义为:容器(container)算法(algorithm)迭代器(iterator)
7.1 STL初识
- 容 器:各种数据结构,如vector,list,deque,set,map等,用来存放数据
- 算 法:各种常用的算法:如sort,find,copy,for_each等
- 迭代器:扮演容器与算法之间的胶合剂
- 仿函数:行为类似函数,可作为算法的某种策略
- 适配器:用来修饰容器或者仿函数或迭代器接口的东西
- 空间配置器:负责空间的配置与管理
7.1.1 容器,算法,迭代器
容器
- 序列式容器
- 关联式容器 算法
- 质变算法
- 非质变算法 迭代器
- 类似指针
7.1.2 vectorc存放自定义数据类型(遍历容器)
class Person
{
public:
Person(string name, int age) {
mName = name;
mAge = age;
}
string mName;
int mAge;
};
void test01() {
vector<Person>v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
Person p6("fff", 60);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
v.push_back(p6);
for (vector <Person>::iterator it = v.begin(); it != v.end(); it++) {
cout << "Name= " << (*it).mName << "Age= " << (*it).mAge << endl;//it为指针(迭代器)
}
}
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);
Person p6("fff", 60);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
v.push_back(&p6);
for (vector <Person*>::iterator it = v.begin(); it != v.end(); it++) {
Person* p = (*it);
cout << "Name= " << p->mName << "Age= " << p->mAge << endl;
cout << "Name= " << (*it)->mName << "Age= " << (*it)->mAge << endl;//两者相同
}
}
int main() {
test01();
test02();
}7.1.3 容器嵌套容器
7.2 string容器
7.2.1 基本概念
- char* 是一个指针
- string是一个类,类封装了char*,管理这个字符串,是一个char*型的容器
- 特点:string类内部封装了很多成员方法
7.2.2 构造函数
构造函数原型
//1,默认构造
string s1;
//2,string(const char* s);
const char* str;
string s2(str)="hello word!";
//3,string(const string& str);
string s3(s2);
//,sring(int n,char c);
string s4(10,`a`);7.2.3 赋值操作
//- 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赋给当前字符串`
`string str5;`
str5.assign("hello C++", 5);`
cout << "str5 = " << str5 << endl;`
`string str7;`
str7.assign(10, 'w');`
cout << "str7 = " << str7 << endl;`7.2.4 字符串的拼接
函数原型:
string& operator+=(const char* str);//重载+=操作符string& operator+=(const char c);//重载+=操作符string& operator+=(const string& str);//重载+=操作符string& append(const char *s);//把字符串s连接到当前字符串结尾string& append(const char *s, int n);//把字符串s的前n个字符连接到当前字符串结尾string& append(const string &s);//同operator+=(const string& str)string& append(const string &s, int pos, int n);//字符串s中从pos开始的n个字符连接到字符串结尾
string str1 = "我";
str1 += "爱玩游戏";
string str3 = "I";
str3.append(" love ");
str3.append("game abcde", 4);
//str3.append(str2);
str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末7.2.5 查找与替换
函数原型: 略
string str1 = "abcdefg";
int pos = str1.find("de"); pos = str1.rfind("de");
string str1 = "abcdefg";
str1.replace(1, 3, "1111");
//a1111efg7.2.6 字符串比较
比较方式:
- 字符串比较是按字符的ASCII码进行对比
函数原型: 略
string s1 = "hello";
string s2 = "aello";
int ret = s1.compare(s2);
if (ret == 0) {
cout << "s1 等于 s2" << endl;
}
else if (ret > 0)
{
cout << "s1 大于 s2" << endl;
}
else
{
cout << "s1 小于 s2" << endl;
}7.2.7 字符存取
函数原型: 略
`str[i]==str.at(i)`
7.2.8 插入和删除
函数原型: 略
string str = "hello";
str.insert(1, "111");
str.erase(1, 3); //从1号位置开始3个字符
}7.2.9 子串
函数原型: 略
string str = "abcdefg";
string subStr = str.substr(1, 3);
//bcd
string email = "hello@sina.com";
int pos = email.find("@");
string username = email.substr(0, pos);
cout << "username: " << username << endl;7.3 vector容器
7.3.1 构造函数
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);//通过区间方式进行构造
vector<int> v3(10, 100);
printVector(v3);//10个100
vector<int> v4(v3);
printVector(v4);
}7.3.2 赋值操作
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);//assign
vector<int>v4;
v4.assign(10, 100);
printVector(v4);7.3.2 容量和大小
empty();//判断容器是否为空capacity();//容器的容量size();//返回容器中元素的个数resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除
7.3.3 插入与删除
vector<int> v1;
//尾插
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
printVector(v1);
//尾删
v1.pop_back();
printVector(v1);
//插入
v1.insert(v1.begin(), 100);
printVector(v1);
v1.insert(v1.begin(), 2, 1000);
printVector(v1);
//删除
v1.erase(v1.begin());
printVector(v1);
//清空
v1.erase(v1.begin(), v1.end());
v1.clear();
printVector(v1);7.3.4 数据存取
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的第一个元素为: " << v1.front() << endl;
cout << "v1的最后一个元素为: " << v1.back() << endl;7.3.5 互换容器
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;
//收缩内存
vector<int>(v).swap(v); //匿名对象
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;7.3.6 预留空间
函数原型:
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。
7.4 deque容器
7.4.1 构造函数
函数原型:
deque<T>deqT; //默认构造形式deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。deque(n, elem);//构造函数将n个elem拷贝给本身。deque(const deque &deq);//拷贝构造函数
void printDeque(const deque<int>& d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}//迭代器中的const用法
//deque构造
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);
}7.4.2 赋值操作
deque<int>d3;
d3.assign(d1.begin(), d1.end());
printDeque(d3);
deque<int>d4;
d4.assign(10, 100);
printDeque(d4);7.4.3 大小操作
函数原型:
-
deque.empty();//判断容器是否为空 -
deque.size();//返回容器中元素的个数 -
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。 -
deque.resize(num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。 -
没有容量概念
7.4.4 插入和删除
函数原型:
两端插入操作:
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位置的数据,返回下一个数据的位置。
总结:
- 插入和删除提供的位置是迭代器!
- 尾插 --- push_back
- 尾删 --- pop_back
- 头插 --- push_front
- 头删 --- pop_front
7.4.5 数据存取
函数原型:
at(int idx);//返回索引idx所指的数据operator[];//返回索引idx所指的数据front();//返回容器中第一个数据元素back();//返回容器中最后一个数据元素
7.4.6 排序
功能描述:
- 利用算法实现对deque容器进行排序
算法:
sort(iterator beg, iterator end)//对beg和end区间内元素进行排序
7.4.7 STL 案例1-评委打分
7.5 stack容器
7.5.1 构造函数:
stack<T> stk;//stack采用模板类实现, stack对象的默认构造形式stack(const stack &stk);//拷贝构造函数
7.5.2 赋值操作:
stack& operator=(const stack &stk);//重载等号操作符
7.5.3 数据存取:
push(elem);//向栈顶添加元素pop();//从栈顶移除第一个元素top();//返回栈顶元素
7.5.4 大小操作:
empty();//判断堆栈是否为空size();//返回栈的大小
7.6 queue容器
7.6.1 构造函数:
queue<T> que;//queue采用模板类实现,queue对象的默认构造形式queue(const queue &que);//拷贝构造函数
7.6.2 赋值操作:
queue& operator=(const queue &que);//重载等号操作符
7.6.3 数据存取:
push(elem);//往队尾添加元素pop();//从队头移除第一个元素back();//返回最后一个元素front();//返回第一个元素
7.6.4 大小操作:
empty();//判断堆栈是否为空size();//返回栈的大小
7.7 list容器
7.7.1 构造函数
**函数原型:**
list<T> lst;//list采用采用模板类实现,对象的默认构造形式:list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。list(n,elem);//构造函数将n个elem拷贝给本身。list(const list &lst);//拷贝构造函数。
7.7.2 赋值与交换
**函数原型:**
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。assign(n, elem);//将n个elem拷贝赋值给本身。list& operator=(const list &lst);//重载等号操作符swap(lst);//将lst与本身的元素互换。
7.7.3 大小操作
**函数原型:**
-
size();//返回容器中元素的个数 -
empty();//判断容器是否为空 -
resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。 -
resize(num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。
7.7.4 插入和删除
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);
//300 200 100 10 20 30
printList(L);
//尾删
L.pop_back();
printList(L);
//头删
L.pop_front();
printList(L);
//插入(迭代器)
list<int>::iterator it = L.begin();
L.insert(++it, 1000);
printList(L);
//删除(迭代器)
it = L.begin();
L.erase(++it);
printList(L);
//移除(按值删除)
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);//增加三个“10000”
printList(L);
L.remove(10000);//全删
printList(L);
//清空
L.clear();
printList(L);7.7.5 数据存取
**函数原型:**
-
front();//返回第一个元素。 -
back();//返回最后一个元素。 -
不可用at ,[]表示
7.7.6 反转与排序
**函数原型:**
reverse();//反转链表sort();//链表排序- //所有不支持随机访问迭代器的容器,不可以用标准算法
- 但内部会提供一些算法
排序案例
class Person {
public:
Person(string name, int age , int height) {
m_Name = name;
m_Age = age;
m_Height = height;
}
public:
string m_Name; //姓名
int m_Age; //年龄
int m_Height; //身高
};
bool ComparePerson(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("刘备", 35 , 175);
Person p2("曹操", 45 , 180);
Person p3("孙权", 40 , 170);
Person p4("赵云", 25 , 190);
Person p5("张飞", 35 , 160);
Person p6("关羽", 35 , 200);
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
L.push_back(p6);
for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age
<< " 身高: " << it->m_Height << endl;
}
cout << "---------------------------------" << endl;
L.sort(ComparePerson); //排序
for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age
<< " 身高: " << it->m_Height << endl;
}
}7.8 set/multiset容器
- multiset可以插入重复的数据
7.8.1 构造与赋值
set<int> s1;
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
printSet(s1);
//拷贝构造
set<int>s2(s1);
printSet(s2);
//赋值
set<int>s3;
s3 = s2;
printSet(s3);7.8.2 大小与交换
函数原型:
size();//返回容器中元素的数目empty();//判断容器是否为空swap(st);//交换两个集合容
7.8.3 插入和删除
函数原型:
insert(elem);//在容器中插入元素。clear();//清除所有元素erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。erase(elem);//删除容器中值为elem的元素。
7.8.4 查找和统计
函数原型:
find(key);//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();count(key);//统计key的元素个数
set<int> s1;
//插入
s1.insert(10);
s1.insert(30);
s1.insert(20);
s1.insert(40);
//查找
set<int>::iterator pos = s1.find(30);//用迭代器接住find的位置
if (pos != s1.end())//迭代器对比
{
cout << "找到了元素 : " << *pos << endl;//对迭代器的解引用
}
else
{
cout << "未找到元素" << endl;
}7.8.5 pair对组创建
pair<string, int> p(string("Tom"), 20);
cout << "姓名: " << p.first << " 年龄: " << p.second << endl;
pair<string, int> p2 = make_pair("Jerry", 10);
cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;7.8.6 排序
class MyCompare
{
public:
bool operator()(int v1, int v2) {
return v1 > v2;
}
};
void test01()
{
set<int> s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
s1.insert(50);
//默认从小到大
for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
cout << *it << " ";
}
cout << endl;
//指定排序规则
set<int,MyCompare> s2;
s2.insert(10);
s2.insert(40);
s2.insert(20);
s2.insert(30);
s2.insert(50);
for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
cout << *it << " ";
}
cout << endl;
}自定义数据类型排序
class comparePerson
{
public:
bool operator()(const Person& p1, const Person &p2)
{
//按照年龄进行排序 降序
return p1.m_Age > p2.m_Age;
}
};7.9 map/multimap容器
7.9.1 构造与赋值
void printMap(map<int,int>&m)
{
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key = " << it->first << " value = " << it->second << endl;
}
cout << endl;
}
void test01()
{
map<int,int>m; //默认构造
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
printMap(m);
map<int, int>m2(m); //拷贝构造
printMap(m2);
map<int, int>m3;
m3 = m2; //赋值
printMap(m3);
}7.9.2 大小与交换
函数原型:
size();//返回容器中元素的数目empty();//判断容器是否为空swap(st);//交换两个集合容器
7.9.3 插入和删除
//插入
map<int, int> m;
//第一种插入方式
m.insert(pair<int, int>(1, 10));
//第二种插入方式
m.insert(make_pair(2, 20));
//第三种插入方式
m.insert(map<int, int>::value_type(3, 30));
//第四种插入方式
m[4] = 40;
printMap(m);
//删除
m.erase(m.begin());
printMap(m);
m.erase(3);//按照key删除
printMap(m);
//清空
m.erase(m.begin(),m.end());
m.clear();
printMap(m);7.9.4 查找和统计
函数原型:
find(key);//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();count(key);//统计key的元素个数
7.9.5 排序
class MyCompare {
public:
bool operator()(int v1, int v2) {
return v1 > v2;
}
};
void test01()
{
//默认从小到大排序
//利用仿函数实现从大到小排序
map<int, int, MyCompare> m;
m.insert(make_pair(1, 10));
m.insert(make_pair(2, 20));
m.insert(make_pair(3, 30));
m.insert(make_pair(4, 40));
m.insert(make_pair(5, 50));
for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
cout << "key:" << it->first << " value:" << it->second << endl;
}7.8.10 STL案例2
8. STL - 函数对象
8.1 函数对象
概念:
- 重载函数调用操作符的类,其对象常称为函数对象
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:
函数对象(仿函数)是一个类,不是一个函数
#include <string>
//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
public :
int operator()(int v1,int v2)
{
return v1 + v2;
}
};
void test01()
{
MyAdd myAdd;
cout << myAdd(10, 10) << endl;
}
//2、函数对象可以有自己的状态
class MyPrint
{
public:
MyPrint()
{
count = 0;
}
void operator()(string test)
{
cout << test << endl;
count++; //统计使用次数
}
int count; //内部自己的状态
};
void test02()
{
MyPrint myPrint;
myPrint("hello world");
myPrint("hello world");
myPrint("hello world");
cout << "myPrint调用次数为: " << myPrint.count << endl;
}
//3、函数对象可以作为参数传递
void doPrint(MyPrint &mp , string test)
{
mp(test);
}
void test03()
{
MyPrint myPrint;
doPrint(myPrint, "Hello C++");
}
8.2 谓词
概念:
- 返回bool类型的仿函数称为谓词
- 如果operator()接受一个参数,那么叫做一元谓词
- 如果operator()接受两个参数,那么叫做二元谓词
//1.一元谓词
//仿函数,返回值类型是bool的数据类型称为谓词
struct GreaterFive{
bool operator()(int val) {
return val > 5;
}
};
void test01() {
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());//find—_if语法(f,l,bool)
if (it == v.end()) {
cout << "没找到!" << endl;
}
else {
cout << "找到:" << *it << endl;
}
}#include <vector>
#include <algorithm>
//二元谓词
class MyCompare
{
public:
bool operator()(int num1, int num2)
{
return num1 > num2;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(30);
v.push_back(50);
//默认从小到大
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
cout << "----------------------------" << endl;
//使用函数对象改变算法策略,排序从大到小
sort(v.begin(), v.end(), MyCompare());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}8.3 内建函数对象
概念:
- STL内建了一些函数对象
分类:
- 算术仿函数
- 关系仿函数
- 逻辑仿函数
用法:
- 这些仿函数所产生的对象,用法和一般函数完全相同
- 使用内建函数对象,需要引入头文件
#include<functional>
8.3.1 算术仿函数
功能描述:
- 实现四则运算
- 其中negate是一元运算,其他都是二元运算
仿函数原型:
template<class T> T plus<T>//加法仿函数template<class T> T minus<T>//减法仿函数template<class T> T multiplies<T>//乘法仿函数template<class T> T divides<T>//除法仿函数template<class T> T modulus<T>//取模仿函数template<class T> T negate<T>//取反仿函数
void test01()
{
negate<int> n;
cout << n(50) << endl;
}
//plus
void test02()
{
plus<int> p;
cout << p(10, 20) << endl;
}8.3.2 关系仿函数
功能描述:
- 实现关系对比
仿函数原型:
template<class T> bool equal_to<T>//等于template<class T> bool not_equal_to<T>//不等于template<class T> bool greater<T>//大于template<class T> bool greater_equal<T>//大于等于template<class T> bool less<T>//小于template<class T> bool less_equal<T>//小于等于
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数 大于仿函数
sort(v.begin(), v.end(), greater<int>());8.3.3 逻辑仿函数
功能描述:
- 实现逻辑运算
函数原型:
template<class T> bool logical_and<T>//逻辑与template<class T> bool logical_or<T>//逻辑或template<class T> bool logical_not<T>//逻辑非
vector<bool> v;
v.push_back(true);
v.push_back(false);
v.push_back(true);
v.push_back(false);
//1010
for (vector<bool>::iterator it = v.begin();it!= v.end();it++)
{
cout << *it << " ";
}
cout << endl;
//逻辑非 将v容器搬运到v2中,并执行逻辑非运算
vector<bool> v2;
v2.resize(v.size());
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//01019. STL - 常用算法
概述:
-
算法主要是由头文件
<algorithm><functional><numeric>组成。 -
<algorithm>是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等 -
<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数 -
<functional>定义了一些模板类,用以声明函数对象。
9.1 常用遍历算法
算法简介:
for_each//遍历容器transform//搬运容器到另一个容器中
9.1.1 for_each算法(最常见)
#include <algorithm>
#include <vector>
//普通函数
void print01(int val)
{
cout << val << " ";
}
//函数对象
class print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
//for_each算法基本用法
void test01() {
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//遍历算法
for_each(v.begin(), v.end(), print01);
cout << endl;
for_each(v.begin(), v.end(), print02());
cout << endl;
}9.1.2 transform算法
#include<vector>
#include<algorithm>
//常用遍历算法 搬运 transform
class TransForm//内部还可以做一些逻辑运算
{
public:
int operator()(int val)
{
return val;
}
};
class MyPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>vTarget; //目标容器
vTarget.resize(v.size()); // 目标容器需要提前开辟空间
transform(v.begin(), v.end(), vTarget.begin(), TransForm());
for_each(vTarget.begin(), vTarget.end(), MyPrint());
}
9.2 常用查找算法
算法简介:
find//查找元素find_if//按条件查找元素adjacent_find//查找相邻重复元素binary_search//二分查找法count//统计元素个数count_if//按条件统计元素个数
9.2.1 find算法
void test01() {
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i + 1);
}
//查找容器中是否有 5 这个元素
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if (it == v.end())
{
cout << "没有找到!" << endl;
}
else
{
cout << "找到:" << *it << endl;
}
}
class Person {
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
//重载==(用于查找自定义数据类型)
bool operator==(const Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
return false;
}
public:
string m_Name;
int m_Age;
};
void test02() {
vector<Person> v;
//创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
vector<Person>::iterator it = find(v.begin(), v.end(), p2);
if (it == v.end())
{
cout << "没有找到!" << endl;
}
else
{
cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;
}
}9.2.2 find_if算法
功能描述:
- 按条件查找元素
函数原型:
find_if(iterator beg, iterator end, _Pred);// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // _Pred 函数或者谓词(返回bool类型的仿函数)
9.2.3 adjacent_find算法
功能描述:
- 查找相邻重复元素
函数原型:
adjacent_find(iterator beg, iterator end);// 查找相邻重复元素,返回相邻元素的第一个位置的迭代器 // beg 开始迭代器 // end 结束迭代器
9.2.4 binary_search算法
功能描述:
- 查找指定元素是否存在
函数原型:
bool binary_search(iterator beg, iterator end, value);// 查找指定的元素,查到 返回true 否则false // 注意: 在无序序列中不可用 // beg 开始迭代器 // end 结束迭代器 // value 查找的元素
9.2.5 count算法
功能描述:
- 统计元素个数
函数原型:
count(iterator beg, iterator end, value);// 统计元素出现次数
//自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
bool operator==(const Person & p)//重载==号
{
if (this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};9.2.6 count_if算法
功能描述:
- 按条件统计元素个数
函数原型:
count_if(iterator beg, iterator end, _Pred);// 按条件统计元素出现次数 // beg 开始迭代器 // end 结束迭代器 // _Pred 谓词
class Greater4
{
public:
bool operator()(int val)
{
return val >= 4;
}
};
//内置数据类型
void test01()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(5);
v.push_back(3);
v.push_back(4);
v.push_back(4);
int num = count_if(v.begin(), v.end(), Greater4());
cout << "大于4的个数为: " << num << endl;
}
//自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
class AgeLess35
{
public:
bool operator()(const Person &p)
{
return p.m_Age < 35;
}
};
void test02()
{
vector<Person> v;
Person p1("刘备", 35);
Person p2("关羽", 35);
Person p3("张飞", 35);
Person p4("赵云", 30);
Person p5("曹操", 25);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
int num = count_if(v.begin(), v.end(), AgeLess35());
cout << "小于35岁的个数:" << num << endl;
}9.3 常用排序算法
学习目标:
- 掌握常用的排序算法
算法简介:
sort//对容器内元素进行排序random_shuffle//洗牌 指定范围内的元素随机调整次序merge// 容器元素合并,并存储到另一容器中reverse// 反转指定范围的元素
9.3.1 sort算法
功能描述:
- 对容器内元素进行排序
函数原型:
sort(iterator beg, iterator end, _Pred);// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // _Pred 谓词
//sort默认从小到大排序
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
//从大到小排序
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
}5.3.2 random_shuffle算法
功能描述:
- 洗牌 指定范围内的元素随机调整次序
函数原型:
random_shuffle(iterator beg, iterator end);// 指定范围内的元素随机调整次序 // beg 开始迭代器 // end 结束迭代器
srand((unsigned int)time(NULL));
**总结:**random_shuffle洗牌算法比较实用,使用时记得加随机数种子
5.3.3 merge算法
功能描述:
- 两个容器元素合并,并存储到另一容器中
函数原型:
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);// 容器元素合并,并存储到另一容器中 // 注意: 两个容器必须是有序的 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器
**总结:**merge合并的两个容器必须的有序序列
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10 ; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}
vector<int> vtarget;
//目标容器需要提前开辟空间
vtarget.resize(v1.size() + v2.size());
//合并 需要两个有序序列
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin());
for_each(vtarget.begin(), vtarget.end(), myPrint());
cout << endl;
}9.3.4 reverse算法
功能描述:
- 将容器内元素进行反转
函数原型:
reverse(iterator beg, iterator end);// 反转指定范围的元素 // beg 开始迭代器 // end 结束迭代器
9.4 常用拷贝和替换算法
学习目标:
- 掌握常用的拷贝和替换算法
算法简介:
copy// 容器内指定范围的元素拷贝到另一容器中replace// 将容器内指定范围的旧元素修改为新元素replace_if// 容器内指定范围满足条件的元素替换为新元素swap// 互换两个容器的元素
9.4.1 copy算法
功能描述:
- 容器内指定范围的元素拷贝到另一容器中
函数原型:
copy(iterator beg, iterator end, iterator dest);// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // dest 目标起始迭代器
9.4.2 replace算法
功能描述:
- 将容器内指定范围的旧元素修改为新元素
函数原型:
replace(iterator beg, iterator end, oldvalue, newvalue);// 将区间内旧元素 替换成 新元素 // beg 开始迭代器 // end 结束迭代器 // oldvalue 旧元素 // newvalue 新元素
**总结:**replace会替换区间内满足条件的元素
9.4.3 replace_if算法
功能描述:
- 将区间内满足条件的元素,替换成指定元素
函数原型:
replace_if(iterator beg, iterator end, _pred, newvalue);// 按条件替换元素,满足条件的替换成指定元素 // beg 开始迭代器 // end 结束迭代器 // _pred 谓词 // newvalue 替换的新元素
class ReplaceGreater30
{
public:
bool operator()(int val)
{
return val >= 30;
}
};9.4.4 swap算法
功能描述:
- 互换两个容器的元素
函数原型:
swap(container c1, container c2);// 互换两个容器的元素 // c1容器1 // c2容器2
**总结:**swap交换容器时,注意交换的容器要同种类型
9.5 常用算术生成算法
学习目标:
- 掌握常用的算术生成算法
注意:
- 算术生成算法属于小型算法,使用时包含的头文件为
#include <numeric>
算法简介:
accumulate// 计算容器元素累计总和fill// 向容器中添加元素
5.5.1 accumulate算法
功能描述:
- 计算区间内 容器元素累计总和
函数原型:
accumulate(iterator beg, iterator end, value);// 计算容器元素累计总和 // beg 开始迭代器 // end 结束迭代器 // value 起始值
5.5.2 fill算法
功能描述:
- 向容器中填充指定的元素
函数原型:
fill(iterator beg, iterator end, value);// 向容器中填充元素 // beg 开始迭代器 // end 结束迭代器 // value 填充的值
9.6 常用集合算法
学习目标:
- 掌握常用的集合算法
算法简介:
set_intersection// 求两个容器的交集set_union// 求两个容器的并集set_difference// 求两个容器的差集
9.6.1 set_intersection算法
功能描述:
- 求两个容器的交集
函数原型:
-
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);// 求两个集合的交集 // 注意:两个集合必须是有序序列 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i+5);
}
vector<int> vTarget;
//取两个里面较小的值给目标容器开辟空间
vTarget.resize(min(v1.size(), v2.size()));
//返回目标容器的最后一个元素的迭代器地址
vector<int>::iterator itEnd =
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
}- set_intersection返回值既是交集中最后一个元素的位置
9.6.2 set_union算法
功能描述:
- 求两个集合的并集
函数原型:
-
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);// 求两个集合的并集 // 注意:两个集合必须是有序序列 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器
-
set_union返回值既是并集中最后一个元素的位置
9.6.3 set_difference算法
功能描述:
- 求两个集合的差集
函数原型:
-
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);// 求两个集合的差集 // 注意:两个集合必须是有序序列 // beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器
vector<int> vTarget;
//取两个里面较大的值给目标容器开辟空间
vTarget.resize( max(v1.size() , v2.size()));
//返回目标容器的最后一个元素的迭代器地址
cout << "v1与v2的差集为: " << endl;
vector<int>::iterator itEnd =
set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
cout << "v2与v1的差集为: " << endl;
itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;10. c++案例总结
- 基础案例:通讯录管理系统
- 提高案例:职工管理系统
- 高阶案例:演讲比赛流程管理系统