模板
模板就是建立通用的模具,大大提高复用性
模板类型
函数模板、类模板
函数模板
作用:建立一个通用函数,函数返回类型和形参类型可以不具体指定,用一个虚拟的类型表示
语法:template<typename T>
,下面写函数声明或者定义
#include<iostream>
using namespace std;
交换两个整型数据
//void swap_int(int& a, int& b)
//{
// int temp = a;
// a = b;
// b = temp;
//}
//
交换两个浮点型数据
//void swap_double(double& a, double& b)
//{
// double temp = a;
// a = b;
// b = temp;
//}
//函数模板
//比如对于上面的函数,实现的功能基本一致,因此可以使用模板的方式
template<typename T> //声明模板
void myswap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test01()
{
int a = 10;
int b = 20;
//1 自动类型推导
//myswap(a, b);
//2 显示指定类型
myswap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
int main()
{
test01();
}
a = 20
b = 10
函数模板注意事项
1 模板能够推导出一致的T类型,当然也可以采用诸如template<class T1, class T2>
的写法
2 模板必须确定T的数据类型, 才可以使用
#include<iostream>
using namespace std;
template<class T>
void myswap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
//2 模板必须确定T的数据类型, 才可以使用
template<class T>
void func()
{
cout << "func 调用" << endl;
}
void test01()
{
int a = 10;
int b = 20;
char c = 'c';
myswap(a, b); //正确
//myswap(a, c); //错误, 推导不出一致的T类型
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
void test02()
{
func<int>(); //正确
//func(); //错误
}
int main()
{
test01();
test02();
}
a = 20
b = 10
func 调用
案例——数组排序
#include<iostream>
using namespace std;
//排序算法模板
template<class T>
void mySort(T *arr, int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - i - 1; j++)
{
if (arr[j] < arr[j + 1])
{
T temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//打印数组模板
template<class T>
void printInfo(T* arr, int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
//测试字符数组
void test01()
{
char cArr[] = "badcfe";
int len = sizeof(cArr) / sizeof(cArr[0]);
mySort<char>(cArr, len);
printInfo(cArr, len);
}
//测试整型数组
void test02()
{
int iArr[] = {1, 3, 9, 8, 5, 4, 7};
int len = sizeof(iArr) / sizeof(iArr[0]);
mySort<int>(iArr, len);
printInfo(iArr, len);
}
int main()
{
test01();
test02();
}
f e d c b a
9 8 7 5 4 3 1
普通函数和函数模板的区别
普通函数:可发生隐式类型转换(如char与int类型的相加)
函数模板:自动类型推导不可,显示指定类型可以发生隐式类型转换
#include<iostream>
using namespace std;
//普通函数
int myAdd01(int a, int b)
{
return a + b;
}
//模板函数
template<class T>
T myAdd02(T a, T b)
{
return a + b;
}
void test01()
{
int a = 10;
char b = 'a';
//字符和数字相加,普通函数自动进行隐式类型转换,'a'=97
int c = myAdd01(a, b);
cout << "普通函数: " << c << endl;
}
void test02()
{
int a = 10;
char b = 'a';
//1 自动类型推导,无法自动进行隐式类型转换
//int c = myAdd02(a, b);
//2 显示指定类型
int c = myAdd02<int>(a, b);
cout << "模板函数: " << c << endl;
}
int main()
{
test01();
test02();
}
普通函数: 107
模板函数: 107
普通函数和函数模板的调用规则
- 若普通函数和函数模板都可以实现,优先调用普通函数
- 可以通过空模板参数列表来优先调用函数模板
- 函数模板可以发生重载
- 若函数模板可实现更好的匹配,则优先调用函数模板
#include<iostream>
using namespace std;
void myPrint(int a, int b)
{
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 test01()
{
int a = 10;
int b = 20;
int c = 30;
myPrint(a, b); //1 若普通函数和函数模板都可以实现,优先调用普通函数
myPrint<>(a, b); //2 可以通过空模板参数列表来优先调用函数模板
myPrint(a, b, c); //3 函数模板可以发生重载
char d = 'd';
char e = 'e';
//无需char和int的转换,因此调用函数模板是更好的选择
myPrint(d, e); //4 若函数模板可实现更好的匹配,则优先调用函数模板
}
int main()
{
test01();
}
调用普通函数
调用函数模板
调用重载的函数模板
调用函数模板
模板的重载
可以为特定的数据类型(如数组、类等)提供具体化的模板
关键语句
template<>
bool myCompare(Person & p1, Person& p2)
#include<iostream>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
m_Age = age;
}
string m_Name;
int m_Age;
};
//判断两个数据是否相等
template<class T>
bool myCompare(T& a, T& b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
//利用具体化Person的版本实现代码,具体化优先调用
template<>
bool myCompare(Person & p1, Person& p2)
{
if ((p1.m_Age == p2.m_Age) && (p1.m_Name == p2.m_Name))
{
return true;
}
else
{
return false;
}
}
void test01()
{
int a = 10;
int b = 10;
bool ret = myCompare(a, b);
if (ret)
{
cout << "a = b" << endl;
}
else
{
cout << "a != b" << endl;
}
}
void test02()
{
Person p1("Tom", 10);
Person p2("Tom", 10);
bool ret = myCompare(p1, p2);
if (ret)
{
cout << "p1 = p2" << endl;
}
else
{
cout << "p1 != p2" << endl;
}
}
int main()
{
test01();
test02();
}
a = b
p1 = p2
类模板
作用:建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型表示
语法:template<typename T>
,下面写类
类模板语法
#include<iostream>
using namespace std;
//类模板
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
m_Name = name;
m_Age = age;
}
void showInfo()
{
cout << "name = " << m_Name << endl;
cout << "age = " << m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
void test01()
{
Person<string, int> p1("Tom", 10);
p1.showInfo();
}
int main()
{
test01();
}
name = Tom
age = 10
类模板与函数模板的区别
1 类模板没有自动类型推导的使用方式
2 类模板在模板参数列表中可以有默认参数
#include<iostream>
using namespace std;
template<class NameType, class AgeType=int> //2 类模板在模板参数列表中可以有默认参数
class Person
{
public:
Person(NameType name, AgeType age)
{
m_Name = name;
m_Age = age;
}
void showInfo()
{
cout << "name = " << m_Name << endl;
cout << "age = " << m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
void test01()
{
//Person p("Tom", 10); //1 无法进行自动类型推导
Person<string, int> p("Tom", 10);
p.showInfo();
}
void test02()
{
Person<string> p("Jack", 18); //2 类模板在模板参数列表中可以有默认参数
p.showInfo();
}
int main()
{
test01();
test02();
}
name = Tom
age = 10
name = Jack
age = 18
类模板中成员函数创建时机
普通类中的成员函数一开始就可以创建
类模板中的成员函数在调用时才创建
#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:
//类模板中的成员函数
void func1()
{
obj.showPerson1();
}
void func2()
{
obj.showPerson2();
}
T obj;
};
void test01()
{
Myclass<Person1> m;
m.func1();
//m.func2(); //编译出错,说明函数调用才会创建成员函数
}
int main()
{
test01();
}
Person1 show
类模板对象做函数参数
1 指定传入的类型(最常用)
2 参数模板化
3 整个类模板化
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
m_Name = name;
m_Age = age;
}
void showInfo()
{
cout << "name = " << m_Name << endl;
cout << "age = " << m_Age << endl;
}
T1 m_Name;
T2 m_Age;
};
//1 指定传入类型
void printPerson1(Person<string, int>& p)
{
p.showInfo();
}
void test01()
{
Person<string, int> p("Tom", 10);
printPerson1(p);
}
//2 参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
p.showInfo();
}
void test02()
{
Person<string, int> p("Jack", 18);
printPerson2(p);
}
//3 整个类模板化
template<class T>
void printPerson3(T &p)
{
p.showInfo();
}
void test03()
{
Person<string, int> p("Amy", 25);
printPerson3(p);
}
int main()
{
cout << "指定传入类型" << endl;
test01();
cout << "参数模板化" << endl;
test02();
cout << "整个类模板化" << endl;
test03();
}
指定传入类型
name = Tom
age = 10
参数模板化
name = Jack
age = 18
整个类模板化
name = Amy
age = 25
类模板与继承
1 若子类继承的父类是一个类模板,则子类在声明时需要指出父类T的类型,否则编译器无法给子类分配内存(因为不知道T的数据类型)
2 若想灵活指定父类的T类型,子类也需要为类模板
#include<iostream>
using namespace std;
template<class T>
class Base
{
T m;
};
class Son1 :public Base<int> //指定T类型
{
};
void test01()
{
Son1 s1;
}
//若想灵活指定父类的T类型,子类也需要为类模板
template<class T1, class T2>
class Son2 :public Base<T2>
{
public:
Son2()
{
cout << "Son2(T1)的类型: " << typeid(T1).name() << endl;
cout << "Base(T2)的类型: " << typeid(T2).name() << endl;
}
T1 obj;
};
void test02()
{
Son2<int, char> s2; //Son2的obj为int, Base的obj为char
}
int main()
{
test01();
test02();
}
Son2(T1)的类型: int
Base(T2)的类型: char
类模板成员函数类外实现
类模板中成员函数类外实现时,需要加上模板参数列表
//成员函数类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
m_Name = name;
m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showInfo()
{
cout << "name = " << m_Name << endl;
cout << "age = " << m_Age << endl;
}
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void showInfo();
T1 m_Name;
T2 m_Age;
};
//成员函数类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
m_Name = name;
m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showInfo()
{
cout << "name = " << m_Name << endl;
cout << "age = " << m_Age << endl;
}
void test01()
{
Person<string, int> p("Tom", 18);
p.showInfo();
}
int main()
{
test01();
}
name = Tom
age = 18
类模板分文件编写
背景:类模板成员函数创建时机是在调用阶段,导致分文件编写时,链接不到
解决方法
1 直接包含.cpp源文件,将原来的#include "person.h"改为#include “person.cpp”
2 将声明和实现都写到一个文件里,并更改后缀为.hpp(约定俗成)
person.hpp
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void showInfo();
T1 m_Name;
T2 m_Age;
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
m_Name = name;
m_Age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showInfo()
{
cout << "name = " << m_Name << endl;
cout << "age = " << m_Age << endl;
}
main.cpp
#include<iostream>
#include "person.hpp"
using namespace std;
void test01()
{
Person<string, int> p("Tom", 10);
p.showInfo();
}
int main()
{
test01();
}
name = Tom
age = 10
类模板与友元
全局函数类内实现——直接在类内声明友元
全局函数类外实现——需要提前让编译器知道全局函数的存在
#include<iostream>
using namespace std;
template<class T1, class T2>
class Person
{
//1 全局函数, 类内实现
friend void printInfo(Person<T1, T2>& p)
{
cout << "类内实现" << endl;
cout << "name = " << p.m_Name << endl;
cout << "age = " << p.m_Age << endl;
}
public:
Person(T1 name, T2 age)
{
m_Name = name;
m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
//1 全局函数, 类内实现
void test01()
{
Person<string, int> p("Tom", 18);
printInfo(p);
}
int main()
{
test01();
}
类内实现
name = Tom
age = 18
类模板案例——通用数组类
myArray.hpp
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArray
{
public:
MyArray(int capacity)
{
this->m_Capacity = capacity;
this->m_Size = 0;
//对于Person自定义类,记得提供默认拷贝构造
pAddress = new T[this->m_Capacity];
}
MyArray(const MyArray& arr)
{
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
//深拷贝
this->pAddress = new T[this->m_Capacity];
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator= 防止浅拷贝问题,注意这里是两个MyArray类的=
MyArray& operator=(const MyArray&arr)
{
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->m_Capacity = 0;
this->m_Size = 0;
}
//深拷贝
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
for (int i = 0; i < m_Size; i++)
{
pAddress[i] = arr.pAddress[i];
}
return *this;
}
//尾插法
void push_Back(const T& val)
{
if (this->m_Size == this->m_Capacity)
{
return;
}
this->pAddress[this->m_Size] = val; //数组末尾,插入数据
this->m_Size += 1; //更新数组大小
}
//尾删法
void pop_Back()
{
if (this->m_Size == 0)
{
return;
}
this->m_Size -= 1;
}
//这是类内的方法
//通过下标方式访问数组中的元素, arr[0] = 100
T& operator[](int index)
{
return this->pAddress[index];
}
//返回数组容量
int get_Capacity()
{
return this->m_Capacity;
}
//返回数组大小
int get_Size()
{
return this->m_Size;
}
~MyArray()
{
if (pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
}
private:
T* pAddress; //指针指向堆区开辟的真实数组
int m_Capacity; //数组容量
int m_Size; //数组大小
};
main.cpp
#include<iostream>
#include "myArray.hpp"
using namespace std;
class Person
{
public:
//注意这里要自己提供默认拷贝构造
Person()
{
}
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//输出整型数组
void printIntInfo(MyArray<int>&arr)
{
int len = arr.get_Size();
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
//输出Person数组
void printPersonInfo(MyArray<Person>& p)
{
int len = p.get_Size();
for (int i = 0; i < len; i++)
{
cout << "第" << i << "位信息" << endl;
cout << "name = " << p[i].m_Name << endl;
cout << "age = " << p[i].m_Age << endl;
}
}
//测试整型数据类型
void test01()
{
MyArray<int>arr1(5);
for (int i = 0; i < 5; i++)
{
//尾插
arr1.push_Back(i);
}
cout << "arr1的打印输出如下: " << endl;
//由于传入的是MyArray类的实例对象arr1,因此若想要实现arr1[i]的访问,需要重载运算符
printIntInfo(arr1);
cout << "arr1 capacity = " << arr1.get_Capacity() << endl;
cout << "arr1 size = " << arr1.get_Size() << endl;
cout << "-----------------" << endl;
//拷贝构造调用
MyArray<int>arr2(arr1);
cout << "arr2的打印输出如下: " << endl;
printIntInfo(arr2);
cout << "arr2 capacity = " << arr2.get_Capacity() << endl;
cout << "arr2 size = " << arr2.get_Size() << endl;
//尾删
arr2.pop_Back();
cout << "arr2(尾删后)的打印输出如下: " << endl;
printIntInfo(arr2);
cout << "arr2(尾删后) capacity = " << arr2.get_Capacity() << endl;
cout << "arr2(尾删后) size = " << arr2.get_Size() << endl;
cout << "-----------------" << endl;
}
//测试自定义数据类型
void test02()
{
MyArray<Person> p(10);
Person p1("Tom", 10);
Person p2("Jack", 15);
Person p3("Mike", 20);
Person p4("Amy", 25);
Person p5("Anki", 30);
//尾插法
p.push_Back(p1);
p.push_Back(p2);
p.push_Back(p3);
p.push_Back(p4);
p.push_Back(p5);
//输出信息
printPersonInfo(p);
cout << "p capacity = " << p.get_Capacity() << endl;
cout << "p size = " << p.get_Size() << endl;
}
int main()
{
test01();
test02();
}
arr1的打印输出如下:
0 1 2 3 4
arr1 capacity = 5
arr1 size = 5
-----------------
arr2的打印输出如下:
0 1 2 3 4
arr2 capacity = 5
arr2 size = 5
arr2(尾删后)的打印输出如下:
0 1 2 3
arr2(尾删后) capacity = 5
arr2(尾删后) size = 4
-----------------
第0位信息
name = Tom
age = 10
第1位信息
name = Jack
age = 15
第2位信息
name = Mike
age = 20
第3位信息
name = Amy
age = 25
第4位信息
name = Anki
age = 30
p capacity = 10
p size = 5
STL
C++的面向对象和泛型编程的思想,目的都是提高代码的复用性
STL就是提供一套标准模板,来提高代码的复用性
基本概念
- STL:Standard Template Library,标准模板库
- STL分为:容器(container)、算法(algorithm)、迭代器(iterator)
- 容器和算法之间,通过迭代器进行连接
- STL几乎所有代码都采用了模板类或者模板函数
六大组件
容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
容器
各种数据结构,包括vector、list、deque、set、map等
分为序列式容器和关联式容器
- 序列式容器:强调值的排序,每个元素均有固定的位置
- 关联式容器:二叉树结构
算法
各种常用算法,包括sort、find、copy、for_each等
迭代器
容器和算法之间的胶合剂
算法,要通过迭代器,才能访问容器中的元素
仿函数
行为类似函数,可作为算法的某种策略
适配器
用来修饰容器或者迭代器或者仿函数接口
空间配置器
负责空间的配置和管理
实例1——vector存放内置数据类型
容器:vector
算法:for_each
迭代器:vector<int>::iterator
#include<iostream>
#include <vector>
#include<algorithm> //标准算法的头文件
using namespace std;
void myPrint(int val)
{
cout << val << endl;
}
void test01()
{
//创建了一个vector容器,可视之为数组
vector<int> v;
//向容器中插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
//第一种遍历方式
//通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v.begin(); //起始迭代器
vector<int>::iterator itEnd = v.end(); //结束迭代器
cout << "第一种遍历方式" << endl;
while (itBegin != itEnd)
{
cout << *itBegin << endl;
itBegin += 1;
}
cout << "第二种遍历方式" << endl;
//第二种遍历方式
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
cout << "第三种遍历方式" << endl;
//第三种遍历方式,利用STL提供的遍历算法,回调机制
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
}
第一种遍历方式
10
20
30
40
50
第二种遍历方式
10
20
30
40
50
第三种遍历方式
10
20
30
40
50
实例2——vector存放自定义数据类型
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void test01()
{
cout << "test01" << endl;
vector<Person> v;
Person p1("Tom", 18);
Person p2("Mike", 22);
Person p3("Amy", 26);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
//*it的数据类型为Person
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "name: " << (*it).m_Name << " age: " << (*it).m_Age << endl;
cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
}
}
void test02()
{
cout << "test02" << endl;
vector<Person*> v;
Person p1("Tom", 18);
Person p2("Mike", 22);
Person p3("Amy", 26);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
//*it的数据类型为Person*
for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "name: " << (**it).m_Name << " age: " << (**it).m_Age << endl;
cout << "name: " << (*it)->m_Name << " age: " << (*it)->m_Age << endl;
}
}
int main()
{
test01();
test02();
}
test01
name: Tom age: 18
name: Tom age: 18
name: Mike age: 22
name: Mike age: 22
name: Amy age: 26
name: Amy age: 26
test02
name: Tom age: 18
name: Tom age: 18
name: Mike age: 22
name: Mike age: 22
name: Amy age: 26
name: Amy age: 26
实例3——容器嵌套容器
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
void test01()
{
vector<vector<int>> v;
//内层容器
vector<int> v1;
vector<int> v2;
vector<int> v3;
//内层容器添加数据
for (int i = 0; i < 3; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
}
//外层容器添加数据
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
//外层容器,遍历所有数据
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
}
int main()
{
test01();
}
1 2 3
2 3 4
3 4 5
string容器
string的本质是一个类,类内封装了char*
构造函数
#include<iostream>
#include <algorithm>
using namespace std;
void test01()
{
//默认构造 string()
string s1;
//字符串s初始化 string(const char* s)
const char* str = "Hello World!";
string s2(str);
cout << "s2 = " << s2 << endl;
//拷贝构造 string(const string &s)
string s3(s2);
cout << "s3 = " << s3 << endl;
//n个字符c初始化 string(int n, char c)
string s4(10, 'a');
cout << "s4 = " << s4 << endl;
}
int main()
{
test01();
}
s2 = Hello World!
s3 = Hello World!
s4 = aaaaaaaaaa
赋值操作
#include<iostream>
#include <algorithm>
using namespace std;
void test01()
{
string s1;
s1 = "Hello World!";
cout << "s1 = " << s1 << endl;
string s2;
s2 = s1;
cout << "s2 = " << s2 << endl;
string s3;
s3 = 'a';
cout << "s3 = " << s3 << endl;
string s4;
s4.assign("Hello World");
cout << "s4 = " << s4 << endl;
string s5;
s5.assign("Hello World", 5);
cout << "s5 = " << s5 << endl;
string s6;
s6.assign(s4);
cout << "s6 = " << s6 << endl;
string s7;
s7.assign(10, 'a');
cout << "s7 = " << s7 << endl;
}
int main()
{
test01();
}
s1 = Hello World!
s2 = Hello World!
s3 = a
s4 = Hello World
s5 = Hello
s6 = Hello World
s7 = aaaaaaaaaa
字符串拼接
#include<iostream>
#include <algorithm>
using namespace std;
void test01()
{
string s1;
s1 = "Hello";
s1 += " World";
cout << "s1 = " << s1 << endl;
s1 += "!";
cout << "s1 = " << s1 << endl;
string s2;
s2 = "Yes!";
s1 += s2;
cout << "s1 = " << s1 << endl;
string s3;
s3 = "I";
s3.append(" love");
cout << "s3 = " << s3 << endl;
s3.append(" you!y", 5);
cout << "s3 = " << s3 << endl;
s3.append(s2);
cout << "s3 = " << s3 << endl;
}
int main()
{
test01();
}
s1 = Hello World
s1 = Hello World!
s1 = Hello World!Yes!
s3 = I love
s3 = I love you!
s3 = I love you!Yes!
查找和替换
find、replace
#include<iostream>
#include <string>
using namespace std;
//查找
void test01()
{
string s1;
s1 = "Hello World!";
//找到,返回index,否则返回-1
int pos1 = s1.find('o');
cout << "pos1 = " << pos1 << endl;
//从右往左查找
int pos2 = s1.rfind('o');
cout << "pos2 = " << pos2 << endl;
}
//替换
void test02()
{
string s = "Hello World!";
s.replace(6, 11, "Mike");
cout << "s = " << s << endl;
}
int main()
{
test01();
test02();
}
pos1 = 4
pos2 = 7
s = Hello Mike
字符串比较
#include<iostream>
#include <string>
using namespace std;
void test01()
{
string s1;
s1 = "hello";
string s2;
s2 = "hello";
//s1=s2
int ret1 = s1.compare(s2);
cout << "s1=s2: " << ret1 << endl;
string s3;
s3 = "aello";
//s1>s3
int ret2 = s1.compare(s3);
cout << "s1>s3: " << ret2 << endl;
string s4;
s4 = "zello";
//s1<s4
int ret3 = s1.compare(s4);
cout << "s1<s4: " << ret3 << endl;
}
int main()
{
test01();
}
s1=s2: 0
s1>s3: 1
s1<s4: -1
字符存取
#include<iostream>
#include <string>
using namespace std;
void test01()
{
string s1;
s1 = "hello";
//1 []访问单个字符
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
//2 at方式访问单个字符
for (int i = 0; i < s1.size(); i++)
{
cout << s1.at(i) << " ";
}
cout << endl;
//3 修改单个字符,注意在python中无法修改字符串
s1[0] = 'a';
cout << s1 << endl;
s1.at(0) = 'h';
cout << s1 << endl;
}
int main()
{
test01();
}
h e l l o
h e l l o
aello
hello
插入和删除
#include<iostream>
#include <string>
using namespace std;
void test01()
{
string s1;
s1 = "hello";
//插入
s1.insert(5, " World");
cout << s1 << endl;
//删除
s1.erase(5, s1.size());
cout << s1 << endl;
}
int main()
{
test01();
}
hello World
hello
字串获取
#include<iostream>
#include <string>
using namespace std;
void test01()
{
string s1;
s1 = "hello";
string subStr = s1.substr(0, 2);
cout << "subStr = " << subStr << endl;
}
void test02()
{
string email = "hello@sina.com";
int pos = email.find('@');
cout << "pos = " << pos << endl;
//左闭右开
string userName = email.substr(0, pos);
cout << "userName = " << userName << endl;
}
int main()
{
test01();
test02();
}
subStr = he
pos = 5
userName = hello
vector容器
功能:单端数组,且可以动态扩展,vector容器的迭代器是支持随机访问的迭代器
动态扩展:不是在原空间之后续接新空间,而是寻找更大的内容空间,然后将原数据拷贝到新空间,释放原空间
构造函数
#include<iostream>
#include <vector>
using namespace std;
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个元素方式进行构造
vector<int> v3(5, 1);
printVector(v3);
//拷贝构造
vector<int> v4(v1);
printVector(v4);
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
1 1 1 1 1
0 1 2 3 4 5 6 7 8 9
赋值操作
#include<iostream>
#include <vector>
using namespace std;
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);
//operator=
vector<int> v2 = v1;
printVector(v2);
//assign
vector<int> v3;
v3.assign(v1.begin(), v1.end());
printVector(v3);
vector<int> v4;
v4.assign(10, 1);
printVector(v4);
}
int main()
{
test01();
}
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
1 1 1 1 1 1 1 1 1 1
容量和大小
#include<iostream>
#include <vector>
using namespace std;
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);
if (v1.empty())
{
cout << "v1为空" << endl;
}
else
{
cout << "v1 不为空" << endl;
cout << "v1 Capacity: " << v1.capacity() << endl;
cout << "v1 Size: " << v1.size() << endl;
}
//resize方法, 默认用0填充, 也可以指定填充值,如1
v1.resize(15, 1);
printVector(v1);
//超出部分被删除
v1.resize(5);
printVector(v1);
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
v1 不为空
v1 Capacity: 13
v1 Size: 10
0 1 2 3 4 5 6 7 8 9 1 1 1 1 1
0 1 2 3 4
插入和删除
#include<iostream>
#include <vector>
using namespace std;
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);
//尾删法
v1.pop_back();
printVector(v1);
//插入, 注意第一个参数为迭代器
v1.insert(v1.begin(), 100);
printVector(v1);
//插入n个元素
v1.insert(v1.begin(), 2, 10);
printVector(v1);
//删除
v1.erase(v1.begin());
printVector(v1);
//清空
//v1.erase(v1.begin(), v1.end());
v1.clear();
printVector(v1);
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8
100 0 1 2 3 4 5 6 7 8
10 10 100 0 1 2 3 4 5 6 7 8
10 100 0 1 2 3 4 5 6 7 8
数据存取
#include<iostream>
#include <vector>
using namespace std;
void test01()
{
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;
//利用at方式来访问元素
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
cout << "first element: " << v1.front() << endl;
cout << "last element: " << v1.back() << endl;
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
first element: 0
last element: 9
互换容器
除了互换元素,还有收缩内存空间的作用
#include<iostream>
#include <vector>
using namespace std;
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 = 9; i > -1; i--)
{
v2.push_back(i);
}
cout << "交换前" << endl;
printVector(v1);
printVector(v2);
v1.swap(v2);
cout << "交换后" << endl;
printVector(v1);
printVector(v2);
cout << "----------" << endl;
}
void test02()
{
vector<int> v;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
}
cout << "v capacity = " << v.capacity() << endl;
cout << "v size = " << v.size() << endl;
//造成大量空间浪费
v.resize(3);
cout << "v capacity = " << v.capacity() << endl;
cout << "v size = " << v.size() << endl;
//swap收缩内存空间
//vector<int>(v): 匿名对象,且根据当前已用元素个数(即3个元素)来初始容量
//swap相当于两个对象的指针交换
//匿名对象在当前行执行之后,会自动回收内存
vector<int>(v).swap(v);
cout << "v capacity = " << v.capacity() << endl;
cout << "v size = " << v.size() << endl;
}
int main()
{
test01();
test02();
}
交换前
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
交换后
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
----------
v capacity = 138255
v size = 100000
v capacity = 138255
v size = 3
v capacity = 3
v size = 3
预留空间
作用:减少vector在动态扩展容量时的扩展次数(对于数据量较大的情况)
注意**:vector是动态扩展**,即当空间不够时,会重新寻找另一块更大的内存空间,然后将原数据拷贝到新空间,释放原空间;因此vector的首地址会不断变化。
#include<iostream>
#include <vector>
using namespace std;
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;
int num = 0; //记录开辟内存总次数
int* p = NULL;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
if (p != &v1[0])
{
p = &v1[0];
num += 1;
}
}
//分配了30次空间
cout << "num = " << num << endl;
cout << "-------------" << endl;
}
void test02()
{
vector<int> v1;
//利用reserve预留空间
v1.reserve(100000);
int num = 0; //记录开辟内存总次数
int* p = NULL;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
if (p != &v1[0])
{
p = &v1[0];
num += 1;
}
}
//只分配了1次空间
cout << "num = " << num << endl;
}
int main()
{
test01();
test02();
}
num = 30
-------------
num = 1
deque容器
功能:双端数组,可以对头端进行插入删除操作,因此对头部的插入删除速度比vector快,但访问元素的速度比vector慢,deque容器的迭代器也是支持随机访问的
内部原理:中控器,维护每段缓冲区的内容,缓冲区中存放真实数据,中控器维护的是每个缓冲区的地址;由于deque容器需要通过中控器来访问数据,因此访问速度比vector慢
构造函数
#include<iostream>
#include<deque>
using namespace std;
void printDeque(const deque<int>& d)
{
//使用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, 1);
printDeque(d3);
deque<int> d4(d1);
printDeque(d4);
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
1 1 1 1 1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9
赋值操作
#include<iostream>
#include<deque>
using namespace std;
void printDeque(const deque<int>& d)
{
//使用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);
//operator=赋值
deque<int>d2 = d1;
printDeque(d2);
//assign
deque<int>d3;
d3.assign(d1.begin(), d1.end());
printDeque(d3);
deque<int>d4;
d4.assign(10, 1);
printDeque(d4);
}
int main()
{
test01();
}
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
1 1 1 1 1 1 1 1 1 1
大小操作
注意deque没有容量的概念
#include<iostream>
#include<deque>
using namespace std;
void printDeque(const deque<int>& d)
{
//使用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);
if (d1.empty())
{
cout << "deque为空" << endl;
}
else
{
cout << "deque不为空" << endl;
cout << "d1 size = " << d1.size() << endl;
}
//resize
d1.resize(15, 1);
printDeque(d1);
d1.resize(5);
printDeque(d1);
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
deque不为空
d1 size = 10
0 1 2 3 4 5 6 7 8 9 1 1 1 1 1
0 1 2 3 4
插入和删除
注意插入和删除:提供的位置是迭代器
#include<iostream>
#include<deque>
using namespace std;
void printDeque(const deque<int>& d)
{
//使用const_iterator, 防止修改原有数据
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
//头插
d1.push_front(100);
d1.push_front(200);
printDeque(d1); //[200, 100, 10, 20]
//尾删
d1.pop_back();
printDeque(d1); //[200, 100, 10]
//头删
d1.pop_front();
printDeque(d1); //[100, 10]
cout << "--------------" << endl;
}
void test02()
{
deque<int> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
//头插
d1.push_front(100);
d1.push_front(200);
printDeque(d1); //[200, 100, 10, 20]
//insert插入
d1.insert(d1.begin(), 1000);
printDeque(d1); //[1000, 200, 100, 10, 20]
d1.insert(d1.begin(), 2, 500);
printDeque(d1); //[500, 500, 1000, 200, 100, 10, 20]
//区间insert插入
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, 500, 500, 1000, 200, 100, 10, 20]
cout << "--------------" << endl;
}
void test03()
{
deque<int> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
//头插
d1.push_front(100);
d1.push_front(200);
printDeque(d1); //[200, 100, 10, 20]
//删除第二个元素
d1.erase(d1.begin()+1);
printDeque(d1); //[200, 10, 20]
//区间删除, 清空操作
d1.erase(d1.begin(), d1.end());
//d1.clear();
printDeque(d1);
}
int main()
{
test01();
test02();
test03();
}
200 100 10 20
200 100 10
100 10
--------------
200 100 10 20
1000 200 100 10 20
500 500 1000 200 100 10 20
1 2 3 500 500 1000 200 100 10 20
--------------
200 100 10 20
200 10 20
数据存取
#include<iostream>
#include<deque>
using namespace std;
void test01()
{
deque<int> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
//头插
d1.push_front(100);
d1.push_front(200);
//通过[]方式访问元素
for (int i = 0; i < d1.size(); i++)
{
cout << d1[i] << " ";
}
cout << endl;
//通过at方式访问元素
for (int i = 0; i < d1.size(); i++)
{
cout << d1.at(i) << " ";
}
cout << endl;
cout << "d1 front: " << d1.front() << endl;
cout << "d1 back: " << d1.back() << endl;
}
int main()
{
test01();
}
200 100 10 20
200 100 10 20
d1 front: 200
d1 back: 20
排序
#include<iostream>
#include<deque>
#include<algorithm>
using namespace std;
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> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
//头插
d1.push_front(100);
d1.push_front(200);
printDeque(d1);
//排序
sort(d1.begin(), d1.end());
printDeque(d1);
}
int main()
{
test01();
}
200 100 10 20
10 20 100 200
案例——评委打分
#include<iostream>
#include<vector>
#include<deque>
#include<string>
#include<algorithm>
#include<ctime>
using namespace std;
class Person
{
public:
Person(string name, int score)
{
this->m_Name = name;
this->m_Score = score;
}
string m_Name;
int m_Score;
};
void createPerson(vector<Person>& v)
{
string nameSeed = "ABCDE";
for (int i = 0; i < 5; i++)
{
string name = "";
name += nameSeed[i];
int score = 0;
Person p(name, score);
v.push_back(p);
}
}
void setScore(vector<Person>& v)
{
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
//将评委的分数放到deque容器中
deque<int>d;
for (int i = 0; i < 10; i++)
{
int score = rand() % 41 + 60; //60-100
d.push_back(score);
}
//deque排序
sort(d.begin(), d.end());
//去除最高分和最低分
d.pop_back(); //去除最高分
d.pop_front(); //去除最低分
//取平均分
int sum = 0;
for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
{
sum += *dit;
}
int avg = sum / d.size();
//将平均分赋值到选手
(*it).m_Score = avg;
}
}
void showScore(vector<Person>& v)
{
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "Name: " << (*it).m_Name << " Score: " << (*it).m_Score << endl;
}
}
int main()
{
//随机数种子
srand((unsigned int)time(NULL));
//创建5名选手
vector<Person> v;
createPerson(v);
//打分
setScore(v);
//显示得分
showScore(v);
}
Name: A Score: 81
Name: B Score: 78
Name: C Score: 83
Name: D Score: 79
Name: E Score: 85
stack容器
功能:栈,后进先出
#include<iostream>
#include<stack>
using namespace std;
void test01()
{
stack<int>s;
s.push(10);
s.push(20);
s.push(30);
cout << "s size = " << s.size() << endl;
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
cout << endl;
cout << "s size = " << s.size() << endl;
}
int main()
{
test01();
}
s size = 3
30 20 10
s size = 0
queue容器
#include<iostream>
#include<queue>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void test01()
{
queue<Person>q;
Person p1("Tom", 18);
Person p2("Mike", 25);
Person p3("Amy", 28);
q.push(p1);
q.push(p2);
q.push(p3);
cout << "q size = " << q.size() << endl;
while (!q.empty())
{
cout << "队头 Name = " << q.front().m_Name << " Age = " << q.front().m_Age << endl;
cout << "队尾 Name = " << q.back().m_Name << " Age = " << q.back().m_Age << endl;
cout << endl;
q.pop();
}
cout << "q size = " << q.size() << endl;
}
int main()
{
test01();
}
q size = 3
队头 Name = Tom Age = 18
队尾 Name = Amy Age = 28
队头 Name = Mike Age = 25
队尾 Name = Amy Age = 28
队头 Name = Amy Age = 28
队尾 Name = Amy Age = 28
q size = 0
list容器(链表)
功能:将数据进行链式存储
组成:由一系列结点组成,结点包括数据域(存储数据元素)和指针域(存储下一个结点地址)
优点:可以方便快速地进行插入和删除,采用动态存储分配,不会造成内存浪费和溢出
缺点:不支持随机访问(如数组按照索引访问那样),且空间占用更大(需要存储指针域)
STL的链表是一个双向循环链表
构造函数
#include<iostream>
#include<list>
using namespace std;
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);
printList(l1);
//区间方式构造
list<int>l2(l1.begin(), l1.end());
printList(l2);
//n个元素构造
list<int>l3(3, 1);
printList(l3);
//拷贝构造
list<int>l4(l1);
printList(l4);
}
int main()
{
test01();
}
10 20 30
10 20 30
1 1 1
10 20 30
赋值和交换
#include<iostream>
#include<list>
using namespace std;
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);
printList(l1);
//operator=赋值
list<int>l2;
l2 = l1;
printList(l2);
//区间赋值
list<int>l3;
l3.assign(l1.begin(), l1.end());
printList(l3);
//n个元素赋值
list<int>l4;
l4.assign(5, 1);
printList(l4);
cout << "--------------" << endl;
}
//交换
void test02()
{
list<int>l1;
l1.push_back(10);
l1.push_back(20);
l1.push_back(30);
list<int>l2;
l2.assign(5, 1);
cout << "-----交换前-----" << endl;
printList(l1);
printList(l2);
//交换
l1.swap(l2);
cout << "-----交换后-----" << endl;
printList(l1);
printList(l2);
}
int main()
{
test01();
test02();
}
10 20 30
10 20 30
10 20 30
1 1 1 1 1
--------------
-----交换前-----
10 20 30
1 1 1 1 1
-----交换后-----
1 1 1 1 1
10 20 30
大小操作
#include<iostream>
#include<list>
using namespace std;
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);
printList(l1);
if (l1.empty())
{
cout << "l1为空" << endl;
}
else
{
cout << "l1不为空" << endl;
cout << "l1 size = " << l1.size() << endl;
}
//resize操作
l1.resize(10, 1);
printList(l1);
l1.resize(2);
printList(l1);
}
int main()
{
test01();
}
10 20 30
l1不为空
l1 size = 3
10 20 30 1 1 1 1 1 1 1
10 20
插入和删除
#include<iostream>
#include<list>
using namespace std;
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_front(100);
l1.push_front(200);
l1.push_front(300);
printList(l1); //300 200 100 10 20 30
//尾删
l1.pop_back();
printList(l1); //300 200 100 10 20
//头删
l1.pop_front();
printList(l1); //200 100 10 20
//insert插入
l1.insert(l1.begin(), 1000);
printList(l1); //1000 200 100 10 20
//删除,根据索引
l1.erase(l1.begin());
printList(l1); //200 100 10 20
//移除,根据指定元素值
l1.remove(10);
printList(l1); //200 100 20
//清空
l1.clear();
printList(l1);
}
int main()
{
test01();
}
300 200 100 10 20 30
300 200 100 10 20
200 100 10 20
1000 200 100 10 20
200 100 10 20
200 100 20
数据存取
由于list是链表,因此无法按索引index访问数据,不同于vector容器
#include<iostream>
#include<list>
using namespace std;
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);
cout << "l1 第一个元素: " << l1.front() << endl;
cout << "l1 最后一个元素: " << l1.back() << endl;
//迭代器不支持随机访问
list<int>::iterator it = l1.begin();
//支持双向
it++;
it--;
//不支持随机访问
//it = it + 1; 无法使用
}
int main()
{
test01();
}
l1 第一个元素: 10
l1 最后一个元素: 40
反转和排序
#include<iostream>
#include<list>
using namespace std;
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);
//反转
l1.reverse();
printList(l1);
cout << "--------------" << endl;
}
void test02()
{
list<int>l1;
l1.push_back(10);
l1.push_back(30);
l1.push_back(20);
l1.push_back(40);
printList(l1);
//默认排序,升序
l1.sort();
printList(l1);
}
int main()
{
test01();
test02();
}
10 20 30 40
40 30 20 10
--------------
10 30 20 40
10 20 30 40
排序案例
#include<iostream>
#include<list>
#include<ctime>
using namespace std;
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;
};
//创建人物
void createList(list<Person>& l)
{
string nameSeed = "ABCDE";
for (int i = 0; i < 5; i++)
{
string name = "";
name += nameSeed[i];
int age = rand() % 41 + 20;
int height = rand() % 31 + 160;
Person p(name, age, height);
l.push_back(p);
}
}
//打印信息
void printList(const list<Person>& l)
{
for (list<Person>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << "Name = " << it->m_Name << " Age = " << it->m_Age << " Height = " << it->m_Height << endl;
}
}
//排序规则
bool comparePerson(Person& p1, Person& p2)
{
//按年龄升序,若年龄相等,返回身高更高的那位
if (p1.m_Age == p2.m_Age)
{
//按身高降序
return p1.m_Height > p2.m_Height;
}
return p1.m_Age < p2.m_Age;
}
int main()
{
srand((unsigned int)time(NULL));
list<Person> l;
//创建人物
createList(l);
printList(l);
cout << "----------------------" << endl;
//自定义排序
l.sort(comparePerson);
printList(l);
}
Name = A Age = 50 Height = 187
Name = B Age = 24 Height = 181
Name = C Age = 39 Height = 168
Name = D Age = 51 Height = 189
Name = E Age = 24 Height = 169
----------------------
Name = B Age = 24 Height = 181
Name = E Age = 24 Height = 169
Name = C Age = 39 Height = 168
Name = A Age = 50 Height = 187
Name = D Age = 51 Height = 189
set/multiset容器
功能:所有元素在插入时会自动被排序
本质:属于关联式容器,底层结构使用二叉树实现
区别:set不允许重复元素,multiset允许重复元素
注1:set容器只有insert的方法,没有push_back的方法
注2:set容器的特点就是自动排序+去除重复元素
构造和赋值
#include<iostream>
#include<set>
using namespace std;
void printSet(const set<int>& s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
//默认构造
set<int> s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(20);
s1.insert(30);
printSet(s1);
//拷贝构造
set<int> s2(s1);
printSet(s2);
//赋值
set<int> s3;
s3 = s1;
printSet(s3);
}
int main()
{
test01();
}
10 20 30 40
10 20 30 40
10 20 30 40
大小和交换
#include<iostream>
#include<set>
using namespace std;
void printSet(const set<int>& s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//大小
void test01()
{
set<int> s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
printSet(s1);
if (s1.empty())
{
cout << "s1 为空" << endl;
}
else
{
cout << "s1 不为空" << endl;
cout << "s1 size = " << s1.size() << endl;
}
}
//交换
void test02()
{
set<int> s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
set<int> s2;
s2.insert(100);
s2.insert(400);
s2.insert(300);
s2.insert(200);
cout << "-----交换前-----" << endl;
printSet(s1);
printSet(s2);
//交换
s1.swap(s2);
cout << "-----交换后-----" << endl;
printSet(s1);
printSet(s2);
}
int main()
{
test01();
test02();
}
10 20 30 40
s1 不为空
s1 size = 4
-----交换前-----
10 20 30 40
100 200 300 400
-----交换后-----
100 200 300 400
10 20 30 40
插入和删除
#include<iostream>
#include<set>
using namespace std;
void printSet(const set<int>& s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int> s1;
//插入
s1.insert(40);
s1.insert(10);
s1.insert(20);
s1.insert(30);
printSet(s1); //10 20 30 40
//删除
s1.erase(s1.begin()); //注意删除的是10
printSet(s1);
s1.erase(30);
printSet(s1);
//清空
//s1.erase(s1.begin(), s1.end());
s1.clear();
printSet(s1);
}
int main()
{
test01();
}
10 20 30 40
20 30 40
20 40
查找和统计
注意find的返回值
#include<iostream>
#include<set>
using namespace std;
void printSet(const set<int>& s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//查找
void test01()
{
set<int> s1;
s1.insert(40);
s1.insert(10);
s1.insert(20);
s1.insert(30);
printSet(s1); //10 20 30 40
//注意find返回的是迭代器
set<int>::iterator it = s1.find(30);
if (it != s1.end())
{
cout << "找到元素: " << *it << endl;
}
else
{
cout << "找不到元素" << endl;
}
}
//统计
void test02()
{
set<int> s1;
s1.insert(40);
s1.insert(10);
s1.insert(20);
s1.insert(30);
int num = s1.count(30);
//对于set而言,统计结果非1即0,因为set不允许重复元素
cout << "num = " << num << endl;
}
int main()
{
test01();
test02();
}
10 20 30 40
找到元素: 30
num = 1
set和multiset的区别
#include<iostream>
#include<set>
using namespace std;
void printSet(const set<int>& s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void printMultiset(const multiset<int>& s)
{
for (multiset<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int> s1;
s1.insert(40);
s1.insert(10);
s1.insert(20);
pair<set<int>::iterator, bool> res = s1.insert(20);
if (res.second)
{
cout << "插入成功" << endl;
}
else
{
cout << "插入失败, 重复元素" << endl;
}
s1.insert(30);
printSet(s1); //10 20 30 40
multiset<int> s2;
s2.insert(40);
s2.insert(10);
s2.insert(20);
s2.insert(20);
s2.insert(30);
printMultiset(s2); //10 20 20 30 40
}
int main()
{
test01();
}
插入失败, 重复元素
10 20 30 40
10 20 20 30 40
创建pair对组
#include<iostream>
#include<string>
using namespace std;
void test01()
{
//第一种方式
pair<string, int> p1("Tom", 20);
cout << "Name = " << p1.first << " Age = " << p1.second << endl;
//第二种方式
pair<string, int> p2 = make_pair("Amy", 18);
cout << "Name = " << p2.first << " Age = " << p2.second << endl;
}
int main()
{
test01();
}
Name = Tom Age = 20
Name = Amy Age = 18
排序
利用仿函数,可以改变排序规则
class myCompare
{
public:
//仿函数,注意后面加const
bool operator()(int v1, int v2) const
{
//降序
return v1 > v2;
}
};
内置数据类型
#include<iostream>
#include<set>
using namespace std;
//set容器排序
class myCompare
{
public:
//仿函数,注意后面加const
bool operator()(int v1, int v2) const
{
//降序
return v1 > v2;
}
};
void test01()
{
//默认排序为升序
set<int> s1;
s1.insert(20);
s1.insert(10);
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(20);
s2.insert(10);
s2.insert(30);
s2.insert(50);
for (set<int, myCompare>::iterator it = s2.begin(); it != s2.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
test01();
}
10 20 30 50
50 30 20 10
自定义数据类型
#include<iostream>
#include<set>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//set容器排序
class myCompare
{
public:
//仿函数
bool operator()(const Person &p1, const Person &p2) const
{
//按照年龄升序
return p1.m_Age < p2.m_Age;
}
};
void test01()
{
//根据年龄升序
set<Person, myCompare> s;
Person p1("Tom", 30);
Person p2("Mike", 18);
Person p3("Amy", 25);
s.insert(p1);
s.insert(p2);
s.insert(p3);
for (set<Person, myCompare>::iterator it = s.begin(); it != s.end(); it++)
{
cout << "Name = " << it->m_Name << " Age = " << it->m_Age << endl;
}
}
int main()
{
test01();
}
Name = Mike Age = 18
Name = Amy Age = 25
Name = Tom Age = 30
map/mulltimap容器
功能:map的所有元素都是pair,键值对(key, value)的形式,且所有元素会根据元素的key来自动排序
本质:map/mulltimap容器属于关联式容器,底层结构使用二叉树实现
优点:可以根据key值快速找到value值
区别:map不允许重复key值,multimap允许重复key值
构造和赋值
注意下面的代码段
//默认构造
map<int, int> m;
m.insert(pair<int, int>(1, 10)); //key=1, value=10
#include<iostream>
#include<map>
using namespace std;
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)); //key=1, value=10
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(4, 40));
printMap(m);
//拷贝构造
map<int, int> m2(m);
printMap(m2);
//赋值
map<int, int> m3 = m2;
printMap(m3);
}
int main()
{
test01();
}
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
大小和交换
#include<iostream>
#include<map>
using namespace std;
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>(3, 30));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(4, 40));
if (m.empty())
{
cout << "m为空" << endl;
}
else
{
cout << "m不为空" << endl;
cout << "m size = " << m.size() << endl;
}
}
//交换
void test02()
{
map<int, int> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(3, 30));
m1.insert(pair<int, int>(2, 20));
m1.insert(pair<int, int>(4, 40));
map<int, int> m2;
m2.insert(pair<int, int>(1, 100));
m2.insert(pair<int, int>(3, 300));
m2.insert(pair<int, int>(2, 200));
m2.insert(pair<int, int>(4, 400));
cout << "-----交换前-----" << endl;
printMap(m1);
printMap(m2);
m1.swap(m2);
cout << "-----交换后-----" << endl;
printMap(m1);
printMap(m2);
}
int main()
{
test01();
test02();
}
m不为空
m size = 4
-----交换前-----
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
key = 1 value = 100
key = 2 value = 200
key = 3 value = 300
key = 4 value = 400
-----交换后-----
key = 1 value = 100
key = 2 value = 200
key = 3 value = 300
key = 4 value = 400
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
插入和删除
#include<iostream>
#include<map>
using namespace std;
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;
//插入, 使用insert来插入
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(3, 30));
m.insert(make_pair(2, 20));
m.insert(pair<int, int>(4, 40));
printMap(m);
//访问,可以通过key来访问
cout << "key = 2, value = " << m[2] << endl;
cout << endl;
//删除
m.erase(m.begin());
printMap(m);
m.erase(3); //按照key=3删除
printMap(m);
//清空
//m.erase(m.begin(), m.end());
m.clear();
printMap(m);
}
int main()
{
test01();
}
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
key = 2, value = 20
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
key = 2 value = 20
key = 4 value = 40
查找和统计
#include<iostream>
#include<map>
using namespace std;
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>(3, 30));
m.insert(make_pair(2, 20));
m.insert(pair<int, int>(4, 40));
printMap(m);
map<int, int>::iterator it = m.find(3); //查找key=3的迭代器
if (it != m.end())
{
cout << "找到了元素, key = " << (*it).first << " value = " << (*it).second << endl;
}
else
{
cout << "找不到元素" << endl;
}
//map不允许重复元素,因此count结果非1即0
int num = m.count(3);
cout << "num = " << num << endl;
}
int main()
{
test01();
}
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40
找到了元素, key = 3 value = 30
num = 1
排序
利用仿函数,改变排序规则
内置数据类型
#include<iostream>
#include<map>
using namespace std;
class myCompare
{
public:
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
};
void printMap(map<int, int, myCompare>& m)
{
for (map<int, int, myCompare>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key = " << (*it).first << " value = " << (*it).second << endl;
}
cout << endl;
}
void test01()
{
//自定义排序规则, 降序
map<int, int, myCompare> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(3, 30));
m.insert(make_pair(2, 20));
m.insert(pair<int, int>(4, 40));
printMap(m);
}
int main()
{
test01();
}
key = 4 value = 40
key = 3 value = 30
key = 2 value = 20
key = 1 value = 10
自定义数据类型
注1:对于自定义数据类型,必须给定排序规则,否则map容器不知道如何自动排序,与set容器一样
注2:编写仿函数时,比较的两个对象是key,而非value,且记得在函数后面加const
#include<iostream>
#include<map>
using namespace std;
class Person
{
public:
Person(string name)
{
this->m_Name = name;
}
string m_Name;
};
//按照姓名英文字母进行排序,注意比较的是两个key值
class myCompare
{
public:
bool operator()(const Person& p1, const Person& p2) const
{
return p1.m_Name < p2.m_Name;
}
};
void printMap(const map<Person, int, myCompare>& m)
{
for (map<Person, int, myCompare>::const_iterator it = m.begin(); it != m.end(); it++)
{
cout << "Name = " << it->first.m_Name << " Age = " << it->second << endl;
}
}
void test01()
{
Person p1("Tom");
Person p2("Mike");
Person p3("Amy");
Person p4("Bob");
map<Person, int, myCompare> m;
m.insert(make_pair(p1, 18));
m.insert(make_pair(p2, 30));
m.insert(make_pair(p3, 25));
m.insert(pair<Person, int>(p4, 28));
printMap(m);
}
int main()
{
test01();
}
Name = Amy Age = 25
Name = Bob Age = 28
Name = Mike Age = 30
Name = Tom Age = 18
#include<iostream>
#include<vector>
#include<map>
#include<ctime>
using namespace std;
class Person
{
public:
Person(string name, int salary)
{
m_Name = name;
m_salary = salary;
}
string m_Name;
int m_salary;
};
void distribute(multimap <int, Person>& m, vector<Person> &v1, vector<int> &v2)
{
for (vector<Person>::iterator it = v1.begin(); it != v1.end(); it++)
{
int depart = rand() % v2.size();
m.insert(make_pair(v2[depart], (*it)));
}
}
void printMap(multimap<int, Person>& m)
{
for (int i = 0; i < 3; i++)
{
cout << "-----" << i << "-----" << endl;
multimap<int, Person>::iterator pos = m.find(i);
int count = m.count(i);
int index = 0;
for (; pos != m.end() && index < count; pos++, index++)
{
cout << "Name = " << (*pos).second.m_Name << " " << " Salary = " << (*pos).second.m_salary << endl;
}
cout << endl;
}
}
int main()
{
srand((unsigned int)time(NULL));
//创建multimap,存储键值对
multimap<int, Person> m;
//创建员工
vector<Person> v1;
Person p1("A", 1000);
Person p2("B", 1500);
Person p3("C", 1200);
Person p4("D", 1100);
Person p5("E", 1800);
Person p6("F", 1600);
Person p7("G", 1900);
Person p8("H", 1300);
Person p9("I", 1400);
Person p10("J", 1700);
v1.push_back(p1);
v1.push_back(p2);
v1.push_back(p3);
v1.push_back(p4);
v1.push_back(p5);
v1.push_back(p6);
v1.push_back(p7);
v1.push_back(p8);
v1.push_back(p9);
v1.push_back(p10);
//创建部门,0为策划,1为美术,2为研发
vector<int> v2;
v2.push_back(0);
v2.push_back(1);
v2.push_back(2);
//分配部门
distribute(m, v1, v2);
//打印结果
printMap(m);
}
-----0-----
Name = B Salary = 1500
Name = H Salary = 1300
-----1-----
Name = A Salary = 1000
Name = C Salary = 1200
Name = E Salary = 1800
-----2-----
Name = D Salary = 1100
Name = F Salary = 1600
Name = G Salary = 1900
Name = I Salary = 1400
Name = J Salary = 1700
函数对象
概念
- 重载函数调用操作符的类,其对象称为函数对象
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
- 函数对象(仿函数)是一个类,不是一个函数
#include<iostream>
using namespace std;
//函数对象可以像普通函数一样传参调用
class myAdd
{
public:
//仿函数
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
void test01()
{
myAdd myadd;
cout << myadd(10, 10) << endl;
}
//函数对象可以有自己的状态
class myPrint
{
public:
myPrint()
{
this->count = 0;
}
void operator()(string s)
{
cout << s << endl;
this->count += 1;
}
int count; //内部状态
};
void test02()
{
myPrint myprint;
myprint("Hello!");
myprint("Hello!");
myprint("Hello!");
cout << myprint.count << endl;
}
//函数对象可以作为参数传递
void doPrint(myPrint &m, string s)
{
m(s);
}
void test03()
{
myPrint myprint;
doPrint(myprint, "Hello C++");
}
int main()
{
test01();
test02();
test03();
}
20
Hello!
Hello!
Hello!
3
Hello C++
谓词
概念
- 返回bool类型的仿函数称为谓词
- 若operator()接收一个参数,则称之为一元谓词
- 若operator()接收两个参数,则称之为二元谓词
一元谓词
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//定义类,功能为判断是否值大于5
//一元谓词
class upFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//upFive() 匿名函数对象
vector<int>::iterator it = find_if(v.begin(), v.end(), upFive());
if (it == v.end())
{
cout << "找不到" << endl;
}
else
{
cout << "找到了大于5的数字: " << *it << endl;
}
}
int main()
{
test01();
}
找到了大于5的数字: 6
二元谓词
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//二元谓词
class myCompare
{
public:
bool operator()(int val1, int val2)
{
//降序
return val1 > val2;
}
};
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;
//使用函数对象,改为降序
//注意使用时需要加()
sort(v.begin(), v.end(), myCompare());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
test01();
}
10 20 30 40 50
50 40 30 20 10
内建函数对象
引入头文件#include<functional>
算术仿函数
#include<iostream>
#include<functional>
using namespace std;
//negate 一元仿函数 取反
void test01()
{
negate<int> n;
cout << n(50) << endl;
}
//plus 二元仿函数 加法
void test02()
{
plus<int> p;
cout << p(10, 20) << endl;
}
int main()
{
test01();
test02();
}
-50
30
关系仿函数
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//大于 greater
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);
printVector(v);
//自定义降序
//sort(v.begin(), v.end(), myConpare());
sort(v.begin(), v.end(), greater<int>());
printVector(v);
}
int main()
{
test01();
}
10 40 20 30 50
50 40 30 20 10
逻辑仿函数
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
void printVector(vector<bool>& v)
{
for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//逻辑仿函数
void test01()
{
vector<bool> v;
v.push_back(true);
v.push_back(false);
v.push_back(true);
v.push_back(false);
printVector(v);
vector<bool> v2;
v2.resize(v.size());
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
printVector(v2);
}
int main()
{
test01();
}
1 0 1 0
0 1 0 1
STL-常用算法
遍历算法
for_each
遍历容器
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void printvector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void myPrint(int val)
{
cout << val << " ";
}
class myPrint2
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
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);
printvector(v);
//普通函数传入
for_each(v.begin(), v.end(), myPrint);
cout << endl;
//函数对象传入,注意有括号
for_each(v.begin(), v.end(), myPrint2());
cout << endl;
}
int main()
{
test01();
}
10 40 20 30 50
10 40 20 30 50
10 40 20 30 50
transform
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//void printvector(vector<int>& v)
//{
// for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
// {
// cout << *it << " ";
// }
// cout << endl;
//}
//
//void myPrint(int val)
//{
// cout << val << " ";
//}
//
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class Transform
{
public:
int operator()(int val)
{
return val;
}
};
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);
vector<int> v2;
//注意目标容器,需要提前开辟空间
v2.resize(v.size());
transform(v.begin(), v.end(), v2.begin(), Transform());
for_each(v2.begin(), v2.end(), myPrint());
}
int main()
{
test01();
}
10 40 20 30 50
查找算法
find
注:对于自定义数据类型,需要在自定义类里面,重载运算符==号,以便于自定义类型的比较
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//查找内置数据类型
void test01()
{
vector<int> v;
//for (int i = 0; i < 10; i++)
//{
// v.push_back(i);
//}
v.push_back(10);
v.push_back(15);
//查找元素
vector<int>::iterator it = find(v.begin(), v.end(), 15);
if (it == v.end())
{
cout << "Not found!" << endl;
}
else
{
//it为指定位置迭代器, *it为该位置的元素值
cout << "Found: " << *it << endl;
}
}
//查找自定义数据类型
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
m_Age = age;
}
//需要重载==以让find函数知道如何比较Person数据类型
bool operator==(const Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> v;
//创建数据
Person p1("Tom", 16);
Person p2("Jack", 25);
Person p3("Amy", 28);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
vector<Person>::iterator it = find(v.begin(), v.end(), p2);
if (it == v.end())
{
cout << "Not found!" << endl;
}
else
{
cout << "Found: Name is " << (*it).m_Name << " Age is " << (*it).m_Age << endl;
}
}
int main()
{
test01();
test02();
}
Found: 15
Found: Name is Jack Age is 25
find_if
注:注意使用函数对象来作为_Pred
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//查找内置数据类型
class upFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找大于5的元素
vector<int>::iterator it = find_if(v.begin(), v.end(), upFive());
if (it == v.end())
{
cout << "Not found!" << endl;
}
else
{
//it为指定位置迭代器, *it为该位置的元素值
cout << "Found: " << *it << endl;
}
}
//查找自定义数据类型
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
m_Age = age;
}
//需要重载==以让find函数知道如何比较Person数据类型
bool operator==(const Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};
class upTwenty
{
public:
bool operator()(const Person& p)
{
return p.m_Age > 25;
}
};
void test02()
{
vector<Person> v;
//创建数据
Person p1("Tom", 16);
Person p2("Jack", 25);
Person p3("Amy", 28);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
//查找年龄大于20的人
vector<Person>::iterator it = find_if(v.begin(), v.end(), upTwenty());
if (it == v.end())
{
cout << "Not found!" << endl;
}
else
{
cout << "Found: Name is " << (*it).m_Name << " Age is " << (*it).m_Age << endl;
}
}
int main()
{
test01();
test02();
}
Found: 6
Found: Name is Amy Age is 28
adjacent_find
注:注意这两个关键词:相邻、重复
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void test01()
{
vector<int> v;
v.push_back(0);
v.push_back(2);
v.push_back(0);
v.push_back(2);
v.push_back(3);
v.push_back(3);
v.push_back(4);
vector<int>::iterator it = adjacent_find(v.begin(), v.end());
if (it == v.end())
{
cout << "Not found!" << endl;
}
else
{
cout << "Found: " << *it << endl;
}
}
int main()
{
test01();
}
Found: 3
binary_search
注1:该算法只适用于有序序列
注2:返回值为bool类型
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
bool ret = binary_search(v.begin(), v.end(), 5);
if(ret)
{
cout << "Found!" << endl;
}
else
{
cout << "Not found!" << endl;
}
}
int main()
{
test01();
}
Found!
count
注:对于自定义数据类型,需要在自定义类里面,重载运算符==号,以便于自定义类型的比较
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//统计内置数据类型
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(10);
v.push_back(20);
v.push_back(20);
v.push_back(10);
v.push_back(20);
v.push_back(20);
v.push_back(20);
int num = count(v.begin(), v.end(), 20);
cout << "num of 20 is " << num << endl;
}
//统计自定义数据类型
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
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;
};
void test02()
{
vector<Person> v;
//创建数据
Person p1("Tom", 16);
Person p2("Jack", 25);
Person p3("Amy", 28);
Person p4("Tony", 16);
Person p5("Lucy", 16);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person p("Mike", 16);
//统计与Mike同岁数的人数
int num = count(v.begin(), v.end(), p);
cout << "num of age equal p is " << num << endl;
}
int main()
{
test01();
test02();
}
num of 20 is 5
num of age equal p is 3
count_if
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//统计内置数据类型
class upFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//统计大于5的个数
int num = count_if(v.begin(), v.end(), upFive());
cout << "num of >5 is " << num << endl;
}
//统计自定义数据类型
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
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;
};
class upTwentyFive
{
public:
bool operator()(const Person &p)
{
return p.m_Age > 25;
}
};
void test02()
{
vector<Person> v;
//创建数据
Person p1("Tom", 16);
Person p4("Tony", 20);
Person p2("Jack", 25);
Person p3("Amy", 28);
Person p5("Lucy", 30);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//统计年龄大于25岁的人数个数
int num = count_if(v.begin(), v.end(), upTwentyFive());
cout << "num of age > 25 is " << num << endl;
}
int main()
{
test01();
test02();
}
num of >5 is 4
num of age > 25 is 2
排序算法
sort
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);
//sort排序,默认升序
sort(v.begin(), v.end());
//擅用STL库来实现输出
for_each(v.begin(), v.end(), Myprint());
cout << endl;
//sort改变为降序
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
10 20 30 40 50
50 40 30 20 10
random_shuffle
#include<iostream>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
//记得添加随机数种子
srand((unsigned int)time(NULL));
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
for_each(v.begin(), v.end(), Myprint());
cout << endl;
//打乱顺序
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9
9 7 2 6 3 8 4 0 1 5
merge
注:两个容器必须有序,且都是升序/降序
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
cout << "v2: ";
for_each(v2.begin(), v2.end(), Myprint());
cout << endl;
//目标容器,注意提前开辟内存空间
vector<int> v3;
v3.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
cout << "v3: ";
for_each(v3.begin(), v3.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
v1: 0 1 2 3 4 5 6 7 8 9
v2: 1 2 3 4 5 6 7 8 9 10
v3: 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
reverse
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
reverse(v1.begin(), v1.end());
cout << "v1(reverse): ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
v1: 0 1 2 3 4 5 6 7 8 9
v1(reverse): 9 8 7 6 5 4 3 2 1 0
拷贝和替换算法
copy
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
vector<int>v2;
v2.resize(v1.size());
copy(v1.begin(), v1.end(), v2.begin());
cout << "v2: ";
for_each(v2.begin(), v2.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
v2: 0 1 2 3 4 5 6 7 8 9
replace
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
//将所有的2替换为20
replace(v1.begin(), v1.end(), 2, 20);
cout << "v1(replaced): ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
v1: 0 1 2 3 4 5 6 7 8 9
v1(replaced): 0 1 20 3 4 5 6 7 8 9
replace_if
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class Myreplace
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
//将大于5的数字,都替换为10
replace_if(v1.begin(), v1.end(), Myreplace(), 10);
cout << "v1(replaced): ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
v1: 0 1 2 3 4 5 6 7 8 9
v1(replaced): 0 1 2 3 4 5 10 10 10 10
swap
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 10);
}
cout << "交换前" << endl;
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
cout << "v2: ";
for_each(v2.begin(), v2.end(), Myprint());
cout << endl;
swap(v1, v2);
cout << "交换后" << endl;
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
cout << "v2: ";
for_each(v2.begin(), v2.end(), Myprint());
cout << endl;
}
int main()
{
test01();
}
交换前
v1: 0 1 2 3 4 5 6 7 8 9
v2: 10 11 12 13 14 15 16 17 18 19
交换后
v1: 10 11 12 13 14 15 16 17 18 19
v2: 0 1 2 3 4 5 6 7 8 9
算术生成算法
注意是导入库#include<numeric>
accumulate
#include<iostream>
#include<vector>
#include<numeric>
using namespace std;
void test01()
{
vector<int> v1;
for (int i = 0; i <= 100; i++)
{
v1.push_back(i);
}
int total = accumulate(v1.begin(), v1.end(), 0);
cout << "total = " << total << endl;
}
int main()
{
test01();
}
5050
fill
#include<iostream>
#include<vector>
#include<numeric>
#include<algorithm>
using namespace std;
class Mypint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
v1.resize(10);
fill(v1.begin()+1, v1.end(), 100);
for_each(v1.begin()+1, v1.end(), Mypint());
cout << endl;
}
int main()
{
test01();
}
100 100 100 100 100 100 100 100 100
集合算法
set_intersection
注1:求交集的两个集合必须都是有序序列
注2:目标容器开辟空间,需要从两个集合中取最小值
注3:返回值为交集中最后一个元素的迭代器位置
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
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> v3;
v3.resize(min(v1.size(), v2.size()));
vector<int>::iterator it = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
//注意这里使用it而非v3.end(), 因为v3.end()会把v3的开辟空间内的所有元素打印(其他元素为0)
for_each(v3.begin(), it, Myprint());
cout << endl;
for_each(v3.begin(), v3.end(), Myprint());
}
int main()
{
test01();
}
5 6 7 8 9
5 6 7 8 9 0 0 0 0 0
set_union
注1:目标容器开辟空间,需要将两个集合的size相加
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
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> v3;
v3.resize(v1.size() + v2.size());
vector<int>::iterator it = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), it, Myprint());
cout << endl;
}
int main()
{
test01();
}
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
set_difference
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 5);
}
cout << "v1: ";
for_each(v1.begin(), v1.end(), Myprint());
cout << endl;
cout << "v2: ";
for_each(v2.begin(), v2.end(), Myprint());
cout << endl;
vector<int> v3;
v3.resize(max(v1.size(), v2.size()));
vector<int>::iterator it = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
cout << "v1-v2: ";
for_each(v3.begin(), it, Myprint());
cout << endl;
it = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), v3.begin());
cout << "v2-v1: ";
for_each(v3.begin(), it, Myprint());
cout << endl;
}
int main()
{
test01();
}
v1: 0 1 2 3 4 5 6 7 8 9
v2: 5 6 7 8 9 10 11 12 13 14
v1-v2: 0 1 2 3 4
v2-v1: 10 11 12 13 14