浅拷贝和深拷贝
浅拷贝:简单的赋值拷贝操作;会出现堆区内存重复释放的问题;
深拷贝:在堆区中重新申请内存空间,进行操作;
深拷贝语句:
Person(const Person &p)
{
cout << "拷贝构造函数" << endl;
age = p.age;
// 深拷贝
height = new int(*p.height); // 核心部分
}
~Person()
{
// 析构函数将堆区开辟的数据做释放操作
if (height != NULL)
{
delete height;
height = NULL; // 防止野指针
}
cout << "析构函数" << endl;
}
加号运算符重载
class Person
{
public:
// 成员函数
Person operator+(Person &p)
{
Person temp;
temp.a = this->a + p.a;
temp.b = this->b + p.b;
return temp;
}
int a;
int b;
};
void test01()
{
Person p1;
p1.a = 10;
p1.b = 10;
Person p2;
p2.a = 10;
p2.b = 10;
Person p3 = p1 + p2;
cout << p3.a << p3.b << endl;
}
左移运算符重载
左移运算符重载只能时全局函数,千万不要写成成员函数,如果想访问私有的数据成员,可以将重载函数声明为该类的友元函数
不会利用成员函数重载<<
运算符,因为无法实现cout
在左侧
// 全局函数
// 返回值时引用类型的
ostream &operator<<(ostream &cout, Person &p) // 做成友元函数即可
{
cout << "a=" << p.a << " b=" << p.b;
return cout; // 使用了链式编程思想
}
递增运算符重载(++)
前置++
// 成员函数
// 重载前置++运算符
MyInteger operator++()
{
// 先++
m++;
// 再返回
return *this;
}
后置++
// 重载后置++运算符
//这个int代表一个占位参数,用于区分前置和后置递增
MyInteger operator++(int)
{
// 先记录当时的结果
MyInteger temp = *this;
// 再++
m++;
// 最后将记录结果返回
return temp;
}
赋值运算符的重载
c++编译器至少给一个类提供4个函数
1.默认的构造函数(无参,函数体为空)
2.默认的析构函数(无参,函数体为空)
3.默认的拷贝构造函数,对属性进行值拷贝
4.赋值运算符operator=,对属性进行值拷贝
// 成员函数
Person &operator=(Person &p)
{
// 判断是否有属性在堆区,然后再释放,然后再拷贝
if (age != NULL)
{
delete age;
age = NULL;
}
age = new int(*p.age);
return *this;
// *解引用
}
int *age;
关系运算符的重载
// 成员函数
bool operator==(Person &p)
{
if (this->name == p.name && this->age == p.age)
{
return true;
}
return false;
}
bool operator!=(Person &p)
{
if (this->name != p.name && this->age != p.age)
{
return true;
}
return false;
}
函数调用运算符重载
- 函数调用运算符()也可以重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定的方法,非常灵活
class MyPrint
{
public:
void operator()(string test) // 类似于函数的使用,称为仿函数
{
cout << test << endl;
}
};
void MyPrint02(string test)
{
cout << test << endl;
}
// Example2
class myAdd
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
void test02()
{
myAdd add;
add(10, 20);
cout << myAdd()(10, 10); // 匿名(函数)对象
}
void MyPrint02(string test)
{
cout << test << endl;
}
查看对象模型
- 打开Developer Command Prompt for vs 2019
- 盘符名称加
:
跳转至文件位置 cd[sapce] 文件名
进入文件dir
显示文件夹中的所有文件- 使用命令
cl /d1 reportSingleClassLayout[类名][space][文件名]
继承的同名成员处理
子类对象加作用域可以访问到父类同名成员;
如果子类中出现了和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数;
如果想访问到父类被隐藏的同名成员函数,需要加作用域;
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
a = 100;
cout << "b构造函数" << endl;
}
void func()
{
cout << "base " << endl;
}
void func(int a)
{
cout << "1000000" << endl;
}
int a;
};
class Son : public Base
{
public:
Son()
{
a = 200;
cout << "s构造函数" << endl;
}
void func()
{
cout << "son " << endl;
}
int a;
};
void test01()
{
// Base b;
Son s;
cout << s.Base::a;
}
void test02()
{
Son s;
s.Base::func(100);
}
int main()
{
test02();
}
继承同名静态成员处理方式
-
处理方式和继承同名成员处理方式相同;
-
可以直接通过类名的方式直接访问,不需要创建对象;
-
cout << Son::Base::a; //第一个::代表通过类名的方式访问 第二个::代表访问父类的作用域下
静态多态和动态多态的区别:
静态多态的函数地址早绑定 - 编译阶段确定函数地址;
动态多态的函数地址晚绑定 - 运行阶段确定函数地址;
动态多态的满足条件
- 有继承的关系;
- 要重写父类中的基函数;
动态多态的使用
父类的指针或引用 ,执行子类对象;
纯虚函数和抽象类
只要有一个纯虚函数,这个类称为抽象类
抽象类特点:
-
无法实现实例化对象;
-
抽象类的子类,必须重写父类中的纯虚函数,否则也属于抽象类也无法实例化对象;
虚析构和纯虚析构
问题:
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码;
解决方式:
将父类中的析构函数改为虚析构或者是纯虚析构;
共性:
可以解决父类指针释放子类对象;
都需要有具体的函数实现;
区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象;
// 虚析构
virtual ~类名(){}
// 纯虚析构
virtual ~类名()=0;
例子:
#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
virtual void speak() = 0;
Animal()
{
cout << "Animal构造函数" << endl;
}
// 虚析构可以解决,父类指针释放子类对象是不干净的问题
virtual ~Animal() = 0;
};
// 需要声明,也需要实现;
// 有了纯虚析构函数,也个类也是抽象类,无法实现对象实例化
Animal::~Animal()
{
cout << "Animal纯需构造函数" << endl;
}
class Cat : public Animal
{
public:
Cat(string name)
{
cout << "Cat构造函数" << endl;
this->name = new string(name);
}
void speak()
{
cout << *name << ": 喵喵喵~~~~~" << endl;
}
string *name;
~Cat()
{
cout << "Cat析构函数" << endl;
if (name != NULL)
{
delete name;
name = NULL;
}
}
};
void test01()
{
Animal *a = new Cat("Tom");
a->speak();
// 父类的指针在析构时候,不会调用子类中的析构函数,导致子类如果没有堆区属性,出现内存泄漏
delete a;
}
int main()
{
test01();
}
总结:
- 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象;
- 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构;
- 拥有纯虚析构的类也属于抽象类;
文件操作
C++中对文件操作需要包含头文件<fstream>
<ofstream>
:写操作
<ifstream>
:读操作
<fstream>
:读写操作
写文件步骤:
-
包含头文件
#iclude <fstream>
-
创建流对象
ofstream ofs;
-
打开文件
ofs.open(“文件路径”,打开方式);
-
写数据
ofs<<“写入数据”:
-
关闭文件
ofs.close();
文件的打开方式:
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件而打开文件 |
ios::ate | 初始位置:文件末尾 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在先删除,在创建 |
ios::binary | 二进制方式 |
注意:文件的打开方式可以配合使用,利用|
操作符;
文件读入的四种方式
利用is_open
函数可以判断文件是否打开;
第一种:
char buf[1024] = {0};
while (fin >> buf)
{
cout << buf << endl;
}
第二种:
char buf[1024] = {0};
while (fin.getline(buf, sizeof(buf)))
{
cout << buf << endl;
}
第三种:
string buf;
while (getline(fin, buf))
{
cout << buf << endl;
}
第四种:
char c;
while ((c = fin.get()) != EOF)
{
cout << c;
}
fin.close(); // 读完文件要关闭文件
EOF
: End Of File;
普通函数与函数模板调用规则
- 如果函数模板和普通函数都可以调用,要先调用普通函数
- 可以通过空模板参数列表强制调用函数模板
- 函数模板可以发生函数重载
- 如果函数模板可以更好的匹配,优先调用函数模板
模板具体化
#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 <typename T>
bool myCompare(T &a, T &b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
// 利用具体化的Person的版本来实现代码具体化会优先调用
template <>
bool myCompare(Person &a, Person &b)
{
if (a.m_name == b.m_name && a.m_age == b.m_age)
{
return true;
}
return false;
}
void test01()
{
int a = 10;
int b = 20;
bool result = myCompare(a, b);
if (result)
{
cout << "a==b" << endl;
}
else
{
cout << "a!=b" << endl;
}
}
void test02()
{
Person p1("Tom", 10);
Person p2("Tom", 10);
bool result = myCompare<Person>(p1, p2);
if (result)
{
cout << "p1==p2" << endl;
}
else
{
cout << "p1!=p2" << endl;
}
}
int main()
{
test02();
}
类模板和函数模板的区别
- 类模板没有自动类型推导的使用方式;
- 类模板在模板参数列表中可以有默认参数;
类模板中成员函数创建时机
- 普通类中的成员函数一开始就创建了;
- 类模板中的成员函数在调用时才创建;
类模板对象做函数参数
- 指定传入的类型 – 直接显示对象的数据类型
- 参数模板化 – 将对象中的参数变为模板进行传递
- 整个类模板化 – 将这个对象类型模板化进行传递
类模板与继承
- 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也要变为类模板
类模板成员函数类外实现
#include <iostream>
using namespace std;
template <class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
// this->m_name = name;
// this->m_age = age;
}
T1 m_name;
T2 m_age;
void showPerson()
{
cout << this->m_name << this->m_age << endl;
}
};
template <class T1, class T2>
void Person<T1, T2>::showPerson()
{
}
template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_name = name;
this->m_age = age;
}
Vector
数据类型vector<数据类型> 变量名
;
使用的头文件:
#include <vector>
#include <algorithm>
// 标准算法的头文件
方法:
变量名.push_back(数据) // 尾插法
变量名.begin() // 迭代器的第一个元素
变量名.end() // 迭代器的最后一个元素的下一个位置
三种遍历方法:
#include <iostream>
#include <vector>
#include <algorithm> // 标准算法的头文件
using namespace std;
void test01()
{
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();
while (itBegin != itEnd)
{
cout << *itBegin << endl;
itBegin++;
}
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
// 起始 终止 函数
for_each(v.begin(), v.end(), myPrint); // for_each使用头文件#include <algorithm>
}
void myPrint(int val)
{
cout << val << endl;
}
int main()
{
test01();
return 0;
}
vector存储自定义数据类型:
void test02()
{
vector<Person *> v; // 存储指针 一般数据类型是去掉指针
Person p1("aa", 18);
Person p2("bb", 18);
Person p3("cc", 18);
Person p4("dd", 18);
Person p5("ee", 18);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
{
// it的数据类型取决于<>中的数据类型
cout << "name = " << (*it)->m_name << "; age = " << (*it)->m_age << endl;
// cout << "name = " << it->m_name << "; age = " << it->m_age << endl;
}
}
Control type | ID | Caption | function | |
---|---|---|---|---|
CDialong | Demo | |||
CStatic | IDC_TXT | I am Waiting…. | ||
CButton | BTN_GEN | Click | gen |
DLL:Dynamic Linked library
容器嵌套容器
void test01()
{
vector<vector<int> > v;
vector<int> v1;
vector<int> v2;
vector<int> v3;
vector<int> v4;
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
v4.push_back(i + 4);
}
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
for (vector<vector<int> > ::iterator it = v.begin(); it != v.end(); it++)
{
for (vector<int>::iterator it2 = (*it).begin(); it2 != (*it).end(); it2++)
{
cout << *it2;
}
cout << endl;
}
}
String容器
string构造函数
string(); //创建一个空的字符串
string(const char* s); // 使用字符串s初始化
string(const string& str); // 使用一个string对象初始化另一个string对象
string(int n, char c); // 使用n个字符c初始化
string 赋值操作
string& operator=(const char* s); //char*类型字符串赋值当前的字符串
string& operator=(const string &s); // 把字符串s赋值给当前的字符串
string& operator=(char c); // 字符赋值给当前的字符串
string& assign(const char* s); // 把字符串s赋值给当前的字符串
string& assign(const char* s, int n); // 把字符串s的前n个字符赋值给当前的字符串
string& assign(const string &s); // 把字符串s赋值给当前字符串
string& assign(int n,char c); // 把n个字符c赋给当前字符串
string字符串拼接
string& operator+=(const char* s); // 重载+=操作符
string& operator+=(const string &s); // 重载+=操作符
string& operator+=(const char c); // 重载+=操作符
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查找和替换
int find(const string& str,int pos = 0) const; // 查找str第一次出现位置,从pos开始查找
int find(const char* s,int pos = 0) const; // 查找s第一次出现位置,从pos开始查找
int find(const char* s,int pos, int n) const; // 从pos位置查找s的前n个字符第一次位置
int find(const char s,int pos = 0) const; // 查找字符c第一次出现位置
int rfind(const string& str,int pos = npos) const; // 查找str最后一次位置,从pos开始查找
int rfind(const char* s,int pos = npos) const; // 查找s最后一次出现位置,从pos开始查找
int rfind(const char* s,int pos, int n) const; // 从pos查找s的前n个字符最后一次位置
int rfind(const char c,int pos = 0) const; // 查找字符c最后一次出现位置
string& replace(int pos, int n, const string& str) const; // 替换从pos开始n个字符为字符串str
string& replace(int pos, int n, const char* c) const; // 替换从pos开始的n个字符为字符串s
string比较
比较方式:
字符串比较是按字符的ASCLL
码进行对比
相等:返回0;
大于:返回1;
小于:返回-1;
int compare(const string &s) const;
int compare(const char* s) const;
string字符存取
char& operator[](int n); // 通过[]方式取字符
char& at(int n); // 通过at方法获取字符
string插入和删除
string& insert(int pos, const char* s); // 从pos插入字符串
string& insert(int pos, const string* str); // 从pos插入字符串
string& insert(int pos, int n, char c); // 在指定位置插入n个字符c
string& erase(int pos, int n = npos); // 删除从Pos开始的n个字符
string子串
string substr(int pos = 0, int n = npos) const; // 返回由pos开始的n个字符组成的字符串
vector容器
使用时包含头文件:#include <vector>
vector与普通数组区别:
数组是静态的,而vector可以动态扩展;
动态扩展:
并不是在原有空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间;
vector容器的迭代器是支持随机访问的迭代器;
vector构造函数
vector<T> v; // 采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); // 将v[begin(), end()]区间中的元素拷贝给本身
vector(n, elem); // 构造函数将n个elem拷贝给本身
vector(const vector &vec); // 拷贝构造函数
vector赋值操作
vector& operator=(const vector &vec); // 重载赋值运算符
assign(beg, end); // 将[beg, end] 区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身
vector容量和大小
empty(); // 判断容器是否为空
capacity(); // 容器的容量
size(); // 返回容器中的元素个数
resize(int num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(int num,elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
vector插入和删除
push_back(ele); // 尾部插入元素ele
pop_back(); // 删除最后一个元素
insert(const_iterator pos, ele); // 迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count, ele); // 迭代器指向位置pos插入count个元素ele
erase(const_iterator pos); // 删除迭代器指向的元素
erase(const_iterator start, const_iterator end); // 删除迭代器从start到end之间的元素
clear(); // 删除容器中所有元素
vector数据存取
at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素
vector互换容器
swap(vec); // 将vec与本身的元素互换
内存收缩:
vector<int>(v).swap(v); // 匿名对象分配的内存空间,系统会在该语句执行完自动给释放
vector预留空间
可以减少在动态扩展容量时的扩展次数
reserve(int len); // 容器预留len个元素长度,预留位置不初始化,元素不可访问
统计开辟内存次数:
void test01()
{
vector<int> v;
int num;
int *p = NULL;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
num++;
}
}
cout << num;
}
deque
容器
使用时包含头文件:#include <deque>
双端数组,可以对头端进行插入删除操作;
deque
与vector
区别:
-
vector
对于头部的插入删除效率低,数据量越大,效率越低; -
deque
相对而言,对头部的插入删除速度会比vector
快; -
vector
访问元素时的速度会比deque
快,这和两者内部实现有关;
deque
构造函数
deque<T> deqT; // 默认构造形式
deque(beg, end); // 构造函数将[beg, end]区间中的元素拷贝给本身
deque(n, elem); // 构造函数将n个elem拷贝给本身
deque(const deque &dep); // 拷贝构造函数
deque赋值操作
deque& operator=(const deque &deq); // 重载赋值运算符
assign(beg, end); // 将[beg, end]区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身
deque大小操作
deque.empty(); // 判断容器是否为空
deque.size(); // 返回容器中元素的个数
deque.resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
deque插入和删除
push_bakc(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(); // 清空容器的所有数据
arase(beg, end); // 删除[beg, end)区间的数据,返回下一个数据位置
erase(pos); // 删除pos位置的数据,返回下一个数据的位置
deque
数据存取
at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素
deque
排序
使用时包含头文件#include <algorithm>
sort(iterator beg, iterator end); // 对beg和end区间内元素进行排序 默认从小到大
随机数种子
#include <ctime>
srand((unsigned int)time (NULL);
stack容器
概念:stack是一种先进后出的数据结构;
栈中只有栈顶的元素才可以被外界使用,因此栈不允许有遍历行为;
stack构造函数
stack<T> stk; // stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk); // 拷贝构造函数
stack赋值操作
stack& operator=(const stack &stk); // 重载等号操作符
stack 数据存取
push(elem); // 向栈顶添加元素
pop(); // 从栈顶移除第一个元素
top(); // 返回栈顶元素
stack大小操作
empty(); // 判断堆栈是否为空
size(); // 返回栈的大小
queue容器
概念:queue是一种先进先出的数据结构,他有两个出口;
队列容器允许从一端新增元素,从另一端移除元素;
队列中只有对头和队尾可以被外界使用,因此队列不允许有遍历行为;
queue构造函数
queue<T> que; // que采用模板类实现,que对象的默认构造形式
queue(const queue &que); // 拷贝构造函数
queue赋值操作
queue& operator=(const queue &que); // 重载等号操作符
queue数据存取
push(elem); // 向队尾添加元素
pop(); // 从队头移除第一个元素
back(); // 返回最后一个元素
front(); // 返回第一个元素
queue大小操作
empty(); // 判断堆栈是否为空
size(); // 返回栈的大小
list容器
使用头文件#include <list>
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器;
list的优点:
采用动态存储分配,不会造成内存浪费和溢出;
链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素;
list的缺点:
链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大;
List
有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的;
总结:STL
中List
和vector
是两个最常被使用的容器,各有优缺点;
list构造函数
list<T> lst; // list采用模板类实现,对象的默认构造形式
list(beg, end); // 构造函数将[beg, end)区间中的元素拷贝给本身
list(n, elem); // 构造函数将n个elem拷贝给本身
list(const list &lst); // 拷贝构造函数
list赋值和交换
assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身
list& operator=(const list &lst); // 重载等号操作符
swap(lst); // 将lst与本身的元素互换
list大小操作
empty(); // 判断容器是否为空
size(); // 返回容器中元素的个数
resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
list插入和删除
push_back(elem); // 在容器尾部加入一个元素
pop_back(); // 删除容器中最后一个元素
push_front(elem); // 在容器开头插入一个元素
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位置的数据,返回下一个数据的位置。
remove(elem); // 删除容器中所有与elem值匹配的元素。
list数据存取
front(); // 返回第一个元素
back(); // 返回最后一个元素
list容器不可以通过[]或at方式访问数据;
list反转和排序
reverse(); // 反转链表
sort(); // 链表排序 (从小到大)成员函数
// 改变sort的排序规则
bool myCompare(int v1, int v2)
{
return v1 > v2;
}
sort(myCompare)
所有不支持随机访问迭代器的容器,不可以使用标准算法;
不支持随机访问迭代器的容器,内部会提供对应的一些算法;
list自定义数据高级排序
自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序
#include <iostream>
using namespace std;
#include <list>
#include <string>
class Person
{
public:
Person(string name, int age, int height)
{
this->m_name = name;
this->m_age = age;
this->m_height = height;
}
string m_name;
int m_age;
int m_height;
};
bool 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;
}
void test01()
{
list<Person> l;
Person p1("A", 34, 189);
Person p2("b", 34, 19);
Person p3("c", 35, 159);
Person p4("d", 30, 149);
Person p5("e", 24, 199);
Person p6("f", 64, 119);
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_age << it->m_name << it->m_height << endl;
}
cout << "排序后" << endl;
l.sort(comparePerson);
for (list<Person>::iterator it = l.begin(); it != l.end(); it++)
{
cout << it->m_age << it->m_name << it->m_height << endl;
}
}
int main()
{
test01();
}
验证迭代器是否支持随机访问:
list<int>::iterator it = l1.begin();
it++; // 支持双向
it--;
it = it + 1; // 不支持随机访问
set/multiset容器
使用时包含头文件#include <set>
所有元素都会再插入时自动排序
set/multiset属于关联式容器,底层结构使用二叉数实现;
set
和multiset
区别:
set
不允许容器中有重复的元素
multiset
允许容器中由重复元素
set插入数据的同时会返回插入结果,表示插入是否成功;
multiset不会检测数据,因此可以插入重复数据;
set构造和赋值
set<T> st; // 默认构造函数
set(const set &st); // 拷贝构造函数
set& operator=(const set &st); // 重载等号操作符
set大小和交换
size(); // 返回容器中元素的数目
empty(); // 判断容器是否为空
swap(st); // 交换两个集合容器
set插入和删除
insert(elem); // 在容器中插入元素
clear(); // 清楚所有元素
erase(); // 删除pos迭代器所指的元素,返回下一个元素的迭代器
arase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器
arase(elem); // 删除容器中值为eleme的元素
set查找和统计
find(key); // 查找key是否存在,若存在,返回该键的迭代器;若不存在,返回set.end()
count(key); // 统计key的元素个数
pair队组创建
成对出现的数据,利用队组可以返回两个数据;
pair<type, type> p (value1, value2);
pair<type, type> p = make_pair(value1, value2);
// value1调用方式:p.first
// value2调用方式:p.second
set容器排序
自定义数据类型排序必须指定排序规则
利用仿函数,可以改变排序规则
#include <iostream>
using namespace std;
#include <set>
class MyCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void test01()
{
set<int, MyCompare> s2;
s2.insert(1);
s2.insert(2);
s2.insert(3);
s2.insert(4);
s2.insert(6);
s2.insert(5);
for (set<int>::iterator it = s2.begin(); it != s2.end(); it++)
{
cout << *it << endl;
}
}
int main()
{
test01();
}
自定义数据类型排序:
#include <iostream>
#include <set>
using namespace std;
#include <string>
class Person
{
public:
Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
string m_name;
int m_age;
};
class MyCompare
{
public:
bool operator()(const Person &p, const Person &p2)
{
return p.m_age > p2.m_age;
}
};
void test01()
{
set<Person, MyCompare> s;
Person p1("a", 13);
Person p2("b", 1123);
Person p3("c", 103);
Person p4("d", 100);
Person p5("e", 90);
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
s.insert(p5);
for (set<Person>::iterator it = s.begin(); it != s.end(); it++)
{
cout << it->m_age << it->m_name << endl;
}
}
int main()
{
test01();
}
map
/multimap
容器
简介:
map中所有元素都是pair;
pair中第一个元素为key (键值),起到索引作用,第二个元素为value(实值);
所有元素都会根据元素的键值自动排序;
本质:
map/multimap
属于关联式容器,底层结构是用二叉树实现;
优点:
可以根据key值快速找到value值;
map和multimap
区别:
map不允许容器中有重复key值元素;
multimap
允许容器中有重复key值元素;
使用时包含头文件#include <map>
map构造和赋值
map<T1, T2> mp; // map默认构造函数
map(const map &mp); // 拷贝构造函数
map& operator=(const map &mp); // 重载等号运算符
map大小和交换
size(); // 返回容器中元素的数目
empty(); // 判断容器是否为空
swap(); // 交换两个结合容器
map插入和删除
insert(elem); // 在容器中插入元素
clear(); // 清楚所有元素
erase(pos); // 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器
erase(key); // 删除容器中值为key的元素
插入例子:
m.insert(pair<type1, type2>(value1, value2));
m.insert(make_pair(value1, value2));
m.insert(map<type1, type2>::value_type(value1, value2));
m[key]=value; // 不建议用来插入数据,最好用来访问数据
map查找和统计
find(key); // 查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
count(key); // 统计key的元素的个数
map容器排序
利用仿函数,可以改变排序规则
#include <iostream>
#include <map>
using namespace std;
class MyCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void test()
{
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>::iterator it = m.begin(); it != m.end(); it++)
{
cout << it->first << " " << it->second << endl;
}
}
int main()
{
test();
}
对于自定义类型数据,map必须指定排序规则;
STL
-函数对象
概念:
重载函数调用操作符的类,其对象常称为函数对象;
函数对象使用重载的()时,行为类似函数调用,也叫仿函数;
本质:
函数对象(仿函数)是一个类,不是一个函数;
特点:
函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值;
函数对象超出普通函数的概念,函数对象可以有自己的状态;
函数对象可以作为参数传递;
#include <iostream>
using namespace std;
#include <string>
class MyAdd
{
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
void test()
{
MyAdd myAdd;
cout << myAdd(10, 10);
}
class MyPrint
{
public:
void operator()(string test)
{
cout << test << endl;
this->count++;
}
int count;
MyPrint()
{
this->count = 0;
}
};
void doPrint(MyPrint &mp, string test)
{
mp(test);
}
void test02()
{
MyPrint myPrint;
doPrint(myPrint, "ehllo ");
}
void test01()
{
MyPrint myPrint;
myPrint("hwllowe");
myPrint("hwllowe");
myPrint("hwllowe");
myPrint("hwllowe");
cout << myPrint.count;
}
int main()
{
test02();
}
谓词
返回bool
类型的仿函数称为谓词
如果operator()接受一个参数,那么叫一元谓词;
如果operator()接受两个参数,那么叫二元谓词;
一元谓词
#include <iostream>
#include <vector>
using namespace std;
#include <algorithm>
class GreaterFive
{
public:
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()); // 使用了匿名的函数对象
if (it == v.end())
{
cout << "未找到" << endl;
}
else
{
cout << "找到" << endl;
}
}
int main()
{
test01();
}
二元谓词
#include <iostream>
#include <vector>
using namespace std;
#include <algorithm>
class GreaterFive
{
public:
bool operator()(int val, int val1)
{
return val > val1;
}
};
void test01()
{
vector<int> v;
v.push_back(15550);
v.push_back(30);
v.push_back(1310);
v.push_back(1310);
v.push_back(1311230);
sort(v.begin(), v.end(), GreaterFive());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
}
int main()
{
test01();
}
内建函数对象
这些仿函数所产生的对象,用法和一般函数完全相同;
使用内建函数对象,需要引入头文件#include <functional>
算数仿函数
实现四则运算
其中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> // 取反仿函数
#include <iostream>
#include <functional>
using namespace std;
void test()
{
negate<int> n;
cout << n(50);
}
void test01()
{
plus<int> n;
cout << n(1, 2) << endl;
}
// 其它的用法有一样
int main()
{
test01();
system("pause");
}
关系仿函数
实现关系对比
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> // 小于等于
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;
class My
{
public:
bool operator()(int val1, int val2)
{
return val1 > val2;
}
};
void test()
{
vector<int> v;
v.push_back(1);
v.push_back(4);
v.push_back(6);
v.push_back(2);
v.push_back(9);
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
sort(v.begin(), v.end(), greater<int>()); // 内建函数对象
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
}
int main()
{
test();
}
逻辑仿函数
template<class T> bool logical_and<T> // 逻辑与
template<class T> bool logical_or<T> // 逻辑或
template<class T> bool logical_not<T> // 逻辑非
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;
void test()
{
vector<bool> v;
v.push_back(false);
v.push_back(true);
v.push_back(false);
v.push_back(true);
v.push_back(false);
for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
vector<bool> v2;
v2.resize(v.size());
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
}
int main()
{
test();
}
STL
-常用算法
算法主要是由头文件<algorithm>
,<functional>
,<numeric>
组成;
<algorithm>
是所有STL
头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、赋值、修改等等;
<functional>
体积很小,只包括了在序列上面进行简单数学运算的模块函数;
<numeric>
定义了一些模板类,用以声明函数对象;
常用遍历算法
for_each()
for_each(iterator beg, iterator end, _func) //遍历容器
/*
beg 开始迭代器;
end 结束迭代器
_func 函数或者函数对象
*/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print01(int val)
{
cout << val << " ";
}
class print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
// for_each(v.begin(), v.end(), print01);
for_each(v.begin(), v.end(), print02());
}
int main()
{
test();
}
transform()
transform(iterator beg1, iterator end1, iterator beg2, _func) // 搬运容器到另一个容器中
/*
beg1 原容器开始迭代器;
end1 原容器结束迭代器
beg2 目标容器开始迭代器 使用时目标容器要提前开辟空间(resize())
_func 函数或者函数对象
*/
常用查找算法
find
查找元素,找到返回指定元素的迭代器,找不到返回结束迭代器end();
find(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
#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;
}
bool operator==(const Person &a)
{
if (this->m_name == a.m_name && this->m_age == a.m_age)
{
return true;
}
return false;
}
string m_name;
int m_age;
};
void test01()
{
vector<Person> v;
Person p1("aa", 410);
Person p2("bb", 10);
Person p3("cc", 120);
Person p4("dd", 130);
Person p5("ee", 510);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person pp("bb", 10);
vector<Person>::iterator i = find(v.begin(), v.end(), pp);
if (i == v.end())
{
cout << "not found" << endl;
}
else
{
cout << "found it" << endl;
cout << i->m_name << i->m_age << endl;
}
}
void test()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find(v.begin(), v.end(), 41);
if (it == v.end())
{
cout << "not found" << endl;
}
else
{
cout << "found it" << endl;
}
}
int main()
{
test01();
}
find_if
按条件查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置;
find_if(iterator beg, iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 函数或者谓词(返回bool类型的仿函数)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
bool operator==(const Person &a)
{
if (this->m_name == a.m_name && this->m_age == a.m_age)
{
return true;
}
return false;
}
string m_name;
int m_age;
};
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
class GreaterFive01
{
public:
bool operator()(const Person &val)
{
return val.m_age > 5;
}
};
void test01()
{
vector<Person> v;
Person p1("aa", 410);
Person p2("bb", 10);
Person p3("cc", 120);
Person p4("dd", 130);
Person p5("ee", 510);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person pp("bb", 10);
vector<Person>::iterator i = find_if(v.begin(), v.end(), GreaterFive01());
if (i == v.end())
{
cout << "not found" << endl;
}
else
{
cout << "found it" << endl;
cout << i->m_name << i->m_age << endl;
}
}
void test()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator i = find_if(v.begin(), v.end(), GreaterFive());
if (i == v.end())
{
cout << "not found" << endl;
}
else
{
cout << "found it" << endl;
}
}
int main()
{
test01();
}
adjacent_find
查找相邻重复元素,返回相邻元素的第一个位置的迭代器;
adjacent_find(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void test()
{
vector<int> v;
v.push_back(0);
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
v.push_back(9);
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()
{
test();
}
binary_search
二分法查找,查找指定的元素,找到返回ture,否则返回false;
注意:无序序列不可用;
bool binary_search(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void test()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
bool it = binary_search(v.begin(), v.end(), 4);
if (!it)
{
cout << "not found" << endl;
}
else
{
cout << "found it" << endl;
}
}
int main()
{
test();
}
count
统计元素个数
统计自定义数据类型时,需要配合重载operator==
count(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 统计的元素
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
bool operator==(const Person &a)
{
if (this->m_name == a.m_name && this->m_age == a.m_age)
{
return true;
}
return false;
}
string m_name;
int m_age;
};
void test01()
{
vector<Person> v;
Person p1("aa", 10);
Person p2("bb", 10);
Person p3("aa", 10);
Person p4("dd", 130);
Person p5("ee", 510);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person p("aa", 10);
int i = count(v.begin(), v.end(), p);
cout << i;
}
void test()
{
vector<int> v;
v.push_back(40);
v.push_back(20);
v.push_back(40);
v.push_back(50);
v.push_back(40);
int it = count(v.begin(), v.end(), 40);
cout << it << endl;
}
int main()
{
test01();
}
count_if
按条件统计元素个数
count_if(iterator beg,iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
#include <iostream>
#include <vector>
#include <string>
#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;
};
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 50;
}
};
class GreaterFive01
{
public:
bool operator()(const Person &val)
{
return val.m_age > 51000;
}
};
void test01()
{
vector<Person> v;
Person p1("aa", 410);
Person p2("bb", 10);
Person p3("cc", 120);
Person p4("dd", 130);
Person p5("ee", 510);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person pp("bb", 10);
int i = count_if(v.begin(), v.end(), GreaterFive01());
cout << i << endl;
}
void test()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
int i = count_if(v.begin(), v.end(), GreaterFive());
cout << i << endl;
}
int main()
{
test01();
}
常用排序算法
sort
按值查找元素,找到返回指定位置迭代器,找不到返回结束位置迭代器位置
sort(iterator beg, iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
v.push_back(1);
v.push_back(4);
v.push_back(5);
v.push_back(2);
v.push_back(9);
v.push_back(10);
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
}
random_shuffle
指定范围内的元素随机调整次序
random_shuffle(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
void myPrint(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);
}
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
}
merge
两个容器元素合并,并存储到里一个容器中
新的容器要提前分配空间;
merge(iterator beg1, interator end1, iterator beg2, iterator end2, iterator dest);
// 注意:两个容器必须都是有序的
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
v.push_back(i + 1);
}
vector<int> v3;
v3.resize(v.size() + v2.size());
merge(v.begin(), v.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), v3.end(), myPrint);
}
int main()
{
test01();
}
reverse
将容器内元素进行反转
reverse(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
reverse(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
}
常用拷贝和替换算法
copy
容器中指定范围的元素拷贝到另一个容器中;
目标容器要提前开辟空间;
copy(iterator beg, iterator end, iterator dest);
// beg 开始迭代器
// end 结束迭代器
// dest 目标起始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int> v2;
v2.resize(v.size());
copy(v.begin(), v.end(), v2.begin());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
for_each(v2.begin(), v2.end(), myPrint);
}
int main()
{
test01();
}
replace
将容器中指定范围的旧元素修改为新元素
replace(iterator beg, iterator end, oldvalue, newvalue);
// beg 开始迭代器
// end 结束迭代器
// oldvalue 旧元素
// newvalue 新元素
#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(1);
v.push_back(2);
v.push_back(1);
v.push_back(2);
v.push_back(1);
v.push_back(1);
v.push_back(2);
v.push_back(1);
replace(v.begin(), v.end(), 1, 200);
for_each(v.begin(), v.end(), MyPrint());
}
int main()
{
test01();
}
replace_if
将区间内满足条件的元素,替换成指定元素
replace(iterator beg, iterator end, _Pred, newvalue);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
// 替换的新元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class Greater
{
public:
bool operator()(int val)
{
return val > 1;
}
};
void test01()
{
vector<int> v;
v.push_back(1);
v.push_back(20);
v.push_back(1);
v.push_back(2);
v.push_back(1);
v.push_back(10);
v.push_back(2);
v.push_back(11);
replace_if(v.begin(), v.end(), Greater(), 200);
for_each(v.begin(), v.end(), MyPrint());
}
int main()
{
test01();
}
swap
互换两个容器中的元素
swap(container c1, container c2);
// c1 容器1
// c2 容器2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v;
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
v1.push_back(i + 100);
}
v.push_back(999);
swap(v, v1);
for_each(v.begin(), v.end(), MyPrint());
cout << endl;
for_each(v1.begin(), v1.end(), MyPrint());
}
int main()
{
test01();
}
常用算数生成算法
使用头文件#include <numeric>
;
accumulate
计算区间内容器元素累计总和;
accumulate(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 起始值
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
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);
}
int sum = accumulate(v.begin(), v.end(), 0);
cout << sum << endl;
for_each(v.begin(), v.end(), MyPrint());
}
int main()
{
test01();
}
fill
向容器化中填充指定的元素
fill(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 填充的值
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
class MyPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v;
v.resize(10);
fill(v.begin(), v.end(), 1);
for_each(v.begin(), v.end(), MyPrint());
}
int main()
{
test01();
}
常用集合算法
set_intersection
求两个容器的交集
注意:
求交集的两个集合必须是有序列的;
目标容器开辟空间需要从两个容器中取最小;
set_intersection返回值既是交集中最后一个元素;
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
v1.push_back(i + 5);
}
vector<int> v2;
v2.resize(min(v1.size(), v.size()));
vector<int>::iterator it = set_intersection(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());
for_each(v2.begin(), it, myPrint);
}
int main()
{
test01();
}
set_union
求两个容器的并集
注意:
求交集的两个集合必须是有序列的;
目标容器开辟空间需要取两个容器之和;
set_union返回值既是交集中最后一个元素;
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
v1.push_back(i + 5);
}
vector<int> v2;
v2.resize(v1.size() + v.size());
vector<int>::iterator it = set_union(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());
for_each(v2.begin(), it, myPrint);
}
int main()
{
test01();
}
set_difference
求两个容器的差集
注意:
求交集的两个集合必须是有序列的;
目标容器开辟空间需要从两个容器中取最大的;
set_difference返回值既是交集中最后一个元素;
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
v1.push_back(i + 5);
}
vector<int> v2;
v2.resize(max(v1.size(), v.size()));
vector<int>::iterator it = set_difference(v1.begin(), v1.end(), v.begin(), v.end(), v2.begin());
for_each(v2.begin(), it, myPrint);
}
int main()
{
test01();
}