浅拷贝:简单的赋值拷贝操作;会出现堆区内存重复释放的问题;
深拷贝:在堆区中重新申请内存空间,进行操作;
深拷贝语句:
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; }
:
跳转至文件位置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(); }
#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<数据类型> 变量名
;
使用的头文件:
#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(const char* s); // 使用字符串s初始化 string(const string& str); // 使用一个string对象初始化另一个string对象 string(int n, char c); // 使用n个字符c初始化
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& 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个字符连接到字符串结尾
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
比较方式:
字符串比较是按字符的ASCLL
码进行对比
相等:返回0;
大于:返回1;
小于:返回-1;
int compare(const string &s) const; int compare(const char* s) const;
char& operator[](int n); // 通过[]方式取字符 char& at(int n); // 通过at方法获取字符
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 substr(int pos = 0, int n = npos) const; // 返回由pos开始的n个字符组成的字符串
使用时包含头文件:#include <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& operator=(const vector &vec); // 重载赋值运算符 assign(beg, end); // 将[beg, end] 区间中的数据拷贝赋值给本身 assign(n, elem); // 将n个elem拷贝赋值给本身
empty(); // 判断容器是否为空 capacity(); // 容器的容量 size(); // 返回容器中的元素个数 resize(int num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除 resize(int num,elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
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(); // 删除容器中所有元素
at(int idx); // 返回索引idx所指的数据 operator[]; // 返回索引idx所指的数据 front(); // 返回容器中第一个数据元素 back(); // 返回容器中最后一个数据元素
swap(vec); // 将vec与本身的元素互换
内存收缩:
vector<int>(v).swap(v); // 匿名对象分配的内存空间,系统会在该语句执行完自动给释放
可以减少在动态扩展容量时的扩展次数
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& operator=(const deque &deq); // 重载赋值运算符 assign(beg, end); // 将[beg, end]区间中的数据拷贝赋值给本身 assign(n, elem); // 将n个elem拷贝赋值给本身
deque.empty(); // 判断容器是否为空 deque.size(); // 返回容器中元素的个数 deque.resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除 deque.resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
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<T> stk; // stack采用模板类实现,stack对象的默认构造形式 stack(const stack &stk); // 拷贝构造函数
stack& operator=(const stack &stk); // 重载等号操作符
push(elem); // 向栈顶添加元素 pop(); // 从栈顶移除第一个元素 top(); // 返回栈顶元素
empty(); // 判断堆栈是否为空 size(); // 返回栈的大小
概念:queue是一种先进先出的数据结构,他有两个出口;
队列容器允许从一端新增元素,从另一端移除元素;
队列中只有对头和队尾可以被外界使用,因此队列不允许有遍历行为;
queue<T> que; // que采用模板类实现,que对象的默认构造形式 queue(const queue &que); // 拷贝构造函数
queue& operator=(const queue &que); // 重载等号操作符
push(elem); // 向队尾添加元素 pop(); // 从队头移除第一个元素 back(); // 返回最后一个元素 front(); // 返回第一个元素
empty(); // 判断堆栈是否为空 size(); // 返回栈的大小
使用头文件#include <list>
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器;
list的优点:
采用动态存储分配,不会造成内存浪费和溢出;
链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素;
list的缺点:
链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大;
List
有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的;
总结:STL
中List
和vector
是两个最常被使用的容器,各有优缺点;
list<T> lst; // list采用模板类实现,对象的默认构造形式 list(beg, end); // 构造函数将[beg, end)区间中的元素拷贝给本身 list(n, elem); // 构造函数将n个elem拷贝给本身 list(const list &lst); // 拷贝构造函数
assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身 assign(n, elem); // 将n个elem拷贝赋值给本身 list& operator=(const list &lst); // 重载等号操作符 swap(lst); // 将lst与本身的元素互换
empty(); // 判断容器是否为空 size(); // 返回容器中元素的个数 resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除 resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
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值匹配的元素。
front(); // 返回第一个元素 back(); // 返回最后一个元素
list容器不可以通过[]或at方式访问数据;
reverse(); // 反转链表 sort(); // 链表排序 (从小到大)成员函数 // 改变sort的排序规则 bool myCompare(int v1, int v2) { return v1 > v2; } sort(myCompare)
所有不支持随机访问迭代器的容器,不可以使用标准算法;
不支持随机访问迭代器的容器,内部会提供对应的一些算法;
自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序
#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; // 不支持随机访问
使用时包含头文件#include <set>
所有元素都会再插入时自动排序
set/multiset属于关联式容器,底层结构使用二叉数实现;
set
和multiset
区别:
set
不允许容器中有重复的元素
multiset
允许容器中由重复元素
set插入数据的同时会返回插入结果,表示插入是否成功;
multiset不会检测数据,因此可以插入重复数据;
set<T> st; // 默认构造函数 set(const set &st); // 拷贝构造函数 set& operator=(const set &st); // 重载等号操作符
size(); // 返回容器中元素的数目 empty(); // 判断容器是否为空 swap(st); // 交换两个集合容器
insert(elem); // 在容器中插入元素 clear(); // 清楚所有元素 erase(); // 删除pos迭代器所指的元素,返回下一个元素的迭代器 arase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器 arase(elem); // 删除容器中值为eleme的元素
find(key); // 查找key是否存在,若存在,返回该键的迭代器;若不存在,返回set.end() count(key); // 统计key的元素个数
成对出现的数据,利用队组可以返回两个数据;
pair<type, type> p (value1, value2); pair<type, type> p = make_pair(value1, value2); // value1调用方式:p.first // value2调用方式:p.second
自定义数据类型排序必须指定排序规则
利用仿函数,可以改变排序规则
#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<T1, T2> mp; // map默认构造函数 map(const map &mp); // 拷贝构造函数 map& operator=(const map &mp); // 重载等号运算符
size(); // 返回容器中元素的数目 empty(); // 判断容器是否为空 swap(); // 交换两个结合容器
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; // 不建议用来插入数据,最好用来访问数据
find(key); // 查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end() count(key); // 统计key的元素的个数
利用仿函数,可以改变排序规则
#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(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(iterator beg1, iterator end1, iterator beg2, _func) // 搬运容器到另一个容器中 /* beg1 原容器开始迭代器; end1 原容器结束迭代器 beg2 目标容器开始迭代器 使用时目标容器要提前开辟空间(resize()) _func 函数或者函数对象 */
查找元素,找到返回指定元素的迭代器,找不到返回结束迭代器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(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(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(); }
二分法查找,查找指定的元素,找到返回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(); }
统计元素个数
统计自定义数据类型时,需要配合重载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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(); }