C++提高编程
模版
特点:
- 只是一个框架,不可以直接使用
- 通用并不是万能的
泛型主要利用模版
函数模版
语法:
template<typename T>
函数
# include<iostream>
using namespace std;template<typename T>
void MySwap(T& a, T& b) {T temp = a;a = b;b = temp;
}void test01() {int a = 10;int b = 20;MySwap(a, b);cout << a << " " << b << endl;char c = 'a';char d = 'b';MySwap<char>(c, d);cout << c << " " << d << endl;
}int main() {test01();system("pause");return 0;
}
注意事项:
- 自动类型推导,必须推导出一致的数据类型T,才可以使用
- 模版必须确定出T的数据类型才可以使用
# include<iostream>
using namespace std;template<typename T>
void MySwap(T& a, T& b) {T temp = a;a = b;b = temp;
}template<class T>
void func() {cout << "func" << endl;
}void test01() {int a = 10;int b = 20;MySwap(a, b);char c = 'a';//MySwap(c, a);//func();func<int>();
}int main() {test01();system("pause");return 0;
}
普通函数与函数模版的区别:
- 普通函数可以发生自动类型转换
- 函数模版调用时,如果利用自动类型推导,不会发生自动类型转换
- 如果利用显示指定类型的方式,可以发生自动类型转换
# include<iostream>
using namespace std;template<typename T>
T MyAdd1(T a, T b) {return a + b;
}int MyAdd2(int a, int b) {return a + b;
}void test01() {int a = 10;int b = 20;char c = 'a'; // 97int ans = 0;ans = MyAdd2(a, c);cout << ans << endl;//ans = MyAdd1(a, c);ans = MyAdd1<int>(a, c);cout << ans << endl;
}int main() {test01();system("pause");return 0;
}
普通函数与函数模版的调用规则:
- 都可实现,优先调用普通函数
- 可以通过空模版参数列表来强制调用函数模版
- 函数模版也可以重载
- 如果函数模版可以更好的匹配,优先调用函数模版
# include<iostream>
using namespace std;void MySwap(int &a, int &b) {cout << "普通函数" << endl;
}template<typename T>
void MySwap(T &a, T &b) {cout << "函数模版" << endl;
}template<typename T>
void MySwap(T& a, T& b, int x) {cout << "重载函数模版" << endl;
}void test01() {int a = 10;int b = 2;MySwap(a, b);MySwap<>(a, b);MySwap(a, b, 100);char c = 'a';char d = 'b';MySwap(c, d);
}int main() {test01();system("pause");return 0;
}
局限性:
- 传入class类时,需要进行函数模版的重载
# include<iostream>
# include<string>
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;
};template<typename T>
bool MyCompare(T &a, T &b) {if (a == b) {return true;}return false;
}template<> bool MyCompare(Person & a, Person & b) {if (a.m_age == b.m_age && a.m_name == b.m_name) {return true;}return false;
}void test01() {Person p1("张三", 19);Person p2("罗向", 55);Person p3("张三", 19);if (MyCompare(p1, p2)) {cout << "p1 p2 一样" << endl;}else {cout << "p1 p2 不一样" << endl;}if (MyCompare(p1, p3)) {cout << "p1 p3 一样" << endl;}else {cout << "p1 p3 不一样" << endl;}
}int main() {test01();system("pause");return 0;
}
类模版
语法:
template<typename T>
类
# include<iostream>
# include<string>
using namespace std;template <class NameType, class AgeType>
class Person {
public:Person(NameType name, AgeType age) {this->m_name = name;this->m_age = age;}void show() {cout << m_name << " " << m_age << endl;}NameType m_name;AgeType m_age;
};void test01() {Person<string, int> p("孙悟空", 999);p.show();
}int main() {test01();system("pause");return 0;
}
类模版与函数模版区别:
类模版与函数模版区别主要有两点:
- 类模版没有自动类型推导的使用方式
- 类模版在模版参数列表中可以有默认参数
# include<iostream>
# include<string>
using namespace std;template <class NameType, class AgeType = int>
class Person {
public:Person(NameType name, AgeType age) {this->m_name = name;this->m_age = age;}void show() {cout << m_name << " " << m_age << endl;}NameType m_name;AgeType m_age;
};void test01() {//Person p("孙悟空", 999);Person<string> p("财务科", 98);p.show();
}int main() {test01();system("pause");return 0;
}
类模版中成员函数创建时机:
- 普通类中成员函数一开始就可以创建
- 类模版中成员函数在调用时才创建
# include<iostream>
# include<string>
using namespace std;class Person1 {
public:void show1() {cout << 1 << endl;}
};class Person2 {
public:void show2() {cout << 2 << endl;}
};template<class T>
class MyClass {
public:T obj;void func1() {obj.show1();}void func2() {obj.show2();}
};void test01() {MyClass<Person1> c;c.func1();//c.func2();
}int main() {test01();system("pause");return 0;
}
类模版对象做函数参数:
三种传入方式:
- 指定传入的类型(直接显示对象的数据类型)
- 参数模版化(将对象中的参数变为模版进行传递)
- 整个类模版化(将这个对象类型 模版化进行传递)
# include<iostream>
# include<string>
using namespace std;template<class T1, class T2>
class Person {
public:Person(T1 name, T2 age) {this->m_name = name;this->m_age = age;}void showPerson() {cout << m_name << " " << m_age << endl;}T1 m_name;T2 m_age;
};void show1(Person<string, int> &p) {p.showPerson();
}template<class T1, class T2>
void show2(Person<T1, T2> &p) {p.showPerson();
}template<class T>
void show3(T& p) {p.showPerson();
}void test01() {Person<string, int> p("孙悟空", 999);show1(p);show2(p);show3(p);
}int main() {test01();system("pause");return 0;
}
类模版与继承:
注意事项:
- 当子类继承的父类是一个类模版时,子类在声明的时候,要指定出父类中的T类型
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也虚变为类模版
# include<iostream>
# include<string>
using namespace std;template<class T>
class Base {
public:T m;
};class Son1 : public Base<int> {};template<class T1, class T2>
class Son2 : public Base<T2> {T1 obj;
};void test01() {Son2<int, char> s2;
}int main() {test01();system("pause");return 0;
}
类模版成员函数类外实现:
# include<iostream>
# include<string>
using namespace std;template<class T1, class T2>
class Person {
public:Person(T1 name, T2 age);void showPerson();T1 m_name;T2 m_age;
};template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->m_name = name;this->m_age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << m_name << " " << m_age << endl;
}void test01() {Person<string, int> p("猪八戒", 888);p.showPerson();
}int main() {test01();system("pause");return 0;
}
类模版分文件编写:
问题:类模版中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:
- 直接包含
.cpp
源文件 - 将声明和实现写到同一个文件中,更改后缀名为
.hpp
person.h
#pragma once
# include<iostream>
# include<string>
using namespace std;template<class T1, class T2>
class Person {
public:Person(T1 name, T2 age);void showPerson();T1 m_name;T2 m_age;
};
person.cpp
#include "person.h"
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->m_name = name;this->m_age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << m_name << " " << m_age << endl;
}
main.cpp
# include<iostream>
# include<string>
# include "person.cpp"
using namespace std;void test01() {Person<string, int> p("猪八戒", 888);p.showPerson();
}int main() {test01();system("pause");return 0;
}
person.hpp
#pragma once
# include<iostream>
# include<string>
using namespace std;template<class T1, class T2>
class Person {
public:Person(T1 name, T2 age);void showPerson();T1 m_name;T2 m_age;
};template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->m_name = name;this->m_age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << m_name << " " << m_age << endl;
}
main.cpp
# include<iostream>
# include<string>
# include "person.hpp"
using namespace std;void test01() {Person<string, int> p("猪八戒", 888);p.showPerson();
}int main() {test01();system("pause");return 0;
}
类模版与友元:
# include<iostream>
# include<string>
using namespace std;template<class T1, class T2>
class Person;template<class T1, class T2>
void showPerson2(Person<T1, T2> &p) {cout << p.m_name << " " << p.m_age << endl;
}template<class T1, class T2>
class Person {//类内实现friend void showPerson(Person<T1, T2> &p) {cout << p.m_name << " " << p.m_age << endl;};//类外实现friend void showPerson2<>(Person<T1, T2> &p);
public:Person(T1 name, T2 age) {this->m_name = name;this->m_age = age;};
private:T1 m_name;T2 m_age;
};void test01() {Person<string, int> p("猪八", 888);showPerson2(p);
}int main() {test01();system("pause");return 0;
}
STL
基本概念
- STL广义上分为,容器,算法,迭代器
- 容器和算法之间通过迭代器进行无缝连接
六大组件:
容器,算法,迭代器,仿函数,适配器(配接器),空间配置器
- 容器:各种数据结构
- 算法:各种常用算法
- 迭代器:容器与算法之间的胶合剂
- 仿函数:行为类似函数,算法的某种策略
- 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
- 空间配置器:负责空间的配置与管理
容器:
- 序列式容器:强调值的排序
- 关联式容器:二叉树结构
算法:
- 质变算法:运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等
- 非质变算法:运算过程中不会更改区间内的元素的内容。例如查找,计数,遍历等
迭代器:
种类 | 功能 | 支持运算 |
---|---|---|
输入迭代器 | 只读数据 | 只读,支持++ == ! = |
输出迭代器 | 只写数据 | 只写,支持++ |
前向迭代器 | 读写操作,向前推进迭代器 | 读写,支持++ == ! = |
双向迭代器 | 读写操作,向前和向后操作 | 读写,支持++ – |
随机访问迭代器 | 读写操作,跳跃访问任意数据 | 读写,支持++ – [n] -n < <= > >= |
vector存放内置数据类型:
容器:vector
算法:for_each
迭代器:vector<int>::iterator
# include<iostream>
# include<string>
# include<vector>
# include<algorithm>
using namespace std;void MyPrint(int val) {cout << val << endl;
}void test01() {vector<int> v;v.push_back(10);v.push_back(23);v.push_back(90);//第一种vector<int>::iterator isBegin = v.begin();vector<int>::iterator isEnd = v.end();while (isBegin != isEnd) {cout << *isBegin << endl;isBegin++;}//第二种for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << endl;}//第三种for_each(v.begin(), v.end(), MyPrint);
}int main() {test01();system("pause");return 0;
}
vector存放自定义数据类型:
# include<iostream>
# include<string>
# include<vector>
# include<algorithm>
using namespace std;class Person {
public:Person(string name, int age) {this->m_age = age;this->m_name = name;}string m_name;int m_age;
};
void test01() {vector<Person> v1;Person p1("a", 10);Person p2("b", 101);v1.push_back(p1);v1.push_back(p2);for (vector<Person>::iterator it = v1.begin(); it != v1.end(); it++) {cout << (*it).m_name << " " << (*it).m_age << endl;cout << it->m_name << " " << it->m_age << endl;}vector<Person*> v2;Person p3("c", 10);Person p4("d", 101);v2.push_back(&p3);v2.push_back(&p4);for (vector<Person*>::iterator it = v2.begin(); it != v2.end(); it++) {cout << (*it)->m_name << " " << (*it)->m_age << endl;}
}int main() {test01();system("pause");return 0;
}
容器嵌套容器:
# include<iostream>
# include<string>
# include<vector>
# include<algorithm>
using namespace std;void test01() {vector<vector<int>> v;vector<int> v1;vector<int> v2;v1.push_back(1);v1.push_back(2);v2.push_back(3);v2.push_back(5);v.push_back(v1);v.push_back(v2);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();system("pause");return 0;
}
string容器
本质:一个类
string
与char*
区别:
char*
是一个指针string
是一个类,类内部封装了char*
,管理这个字符串,是一个char*
的容器
构造函数:
string();
string(const char* s);
string(const string& str);
string(int n, char c)
void test01() {string s1;const char* str = "abc";string s2(str);cout << s2 << endl;string s3(s2);cout << s3 << endl;string s4(10, 'c');cout << s4 << endl;
}
赋值操作:
string& operator=(const char* s);
string& operator=(const string &s);
string& operator=(char c);
string& assign(const char *s);
string& assign(const char *s, int n);
string& assign(const string &s);
string& assign(int n, char c);
void test01() {string s1;s1 = "abc";cout << s1 << endl;string s2 = s1;cout << s2 << endl;string s3, s4, s5, s6;s3.assign(s1);cout << s3 << endl;s4.assign(s1, 2);cout << s4 << endl;s5.assign("abh");cout << s5 << endl;s6.assign(10, 'e');cout << s6 << endl;
}
字符串拼接:
string& operator+=(const char* str);
string& operator+=(const char c);
string& operator+=(const string& str);
string& append(const char* s);
string& append(const char* s, int n);
string& append(const string &s);
string& append(const string &s, int pos, int n);
void test01() {string s1, s2, s3, s4, s5, s6;s1 = "c";s1 += "abc";cout << s1 << endl;s1 += 'm';cout << s1 << endl;s1 += s1;cout << s1 << endl;s2 = "l";s2.append("hj");cout << s2 << endl;s2.append("abhasahdjhsady", 9);cout << s2 << endl;s2.append(s1);cout << s2 << endl;s2.append(s1, 3, 2);cout << s2 << endl;
}
查找和替换:
int find(const string& str, int pos = 0) const;
int find(const char* s, int pos = 0) const;
int find(const char* s, int pos = 0, int n) const;
int find(const char c, int pos = 0) const;
int rfind(const string& str, int pos = npos) const;
int rfind(const char* s, int pos = npos) const;
int rfind(const char* s, int pos, int n) const;
int rfind(const char c, int pos = 0) const;
string& replace(int pos, int n, const string& str);
string& replace(int pos, int n, const char* s);
void test01() {string s1, s2, s3, s4, s5, s6;s1 = "abcdefg";int ans = 0;ans = s1.find("c");ans = s1.find("fj");ans = s1.rfind("de"); // 从右往左cout << ans << endl;s1.replace(1, 4, "11111");cout << s1 << endl;
}
字符串比较:
按ASCLL
码进行对比
=
返回 0>
返回 1<
返回 -1
原型:
int compare(const string &s) const;
int compare(const char *s) const;
void test01() {string s1, s2, s3, s4, s5, s6;s1 = "abcdefg";s2 = "abcdefg";s3 = "zzz";s4 = "aaa";int ans = 0;ans = s1.compare(s2);ans = s1.compare(s3);ans = s1.compare(s4);cout << ans << endl;
}
字符存取:
char& operator[](int n);
char& at(int n);
void test01() {string s1, s2, s3, s4, s5, s6;s1 = "abcdefg";for (int i = 0; i < s1.size(); i++) {cout << s1[i] << " " << s1.at(i) << endl;}
}
插入和删除:
string& insert(int pos, const char* s);
string& insert(int pos, const string& s);
string& insert(int pos, int n, char c);
string& erase(int pos, int n = npos);
void test01() {string s1, s2, s3, s4, s5, s6;s1 = "abcdefg";s2 = "cde";s1.insert(2,"zzz");s1.insert(3, s2);s1.insert(1, 10, 'a');s1.erase(1, 10);cout << s1 << endl;
}
子串:
string substr(int pos = 0, int n = npos) const
void test01() {string s1, s2, s3, s4, s5, s6;s1 = "abcdefg";s2 = s1.substr(3, 5);cout << s2 << endl;
}
vector容器
与数组非常相似,也称为单端数组,与数组的区别是可以动态扩展
动态扩展:
- 不是在原空间之后接新空间,而是找更大的内存空间,将原数据拷贝到新空间
构造函数:
vector<T> v;
vector(v.begin(), v.end());
vector(n, elem);
vector(const vector &vec)
void test01() {vector<int> v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}PrintVector(v1);vector<int> v2(v1.begin(), v1.end());PrintVector(v2);vector<int> v3(10, 10);PrintVector(v3);vector<int> v4(v3);PrintVector(v4);
}
赋值操作:
vector& operator=(const vector &vec);
assign(beg, end);
assign(n, elem);
void test01() {vector<int> v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}PrintVector(v1);vector<int> v2 = v1;PrintVector(v2);vector<int> v3, v4;v3.assign(v2.begin(), v2.end());PrintVector(v3);v4.assign(10, 12);PrintVector(v4);
}
容量和大小:
empty();
capacity();
size();
resize(int num);
resize(int num, elem);
void test01() {vector<int> v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}PrintVector(v1);if (v1.empty()) {cout << "空" << endl;}else {cout << v1.size() << endl;cout << v1.capacity() << endl;}v1.resize(20);cout << v1.size() << " " << v1.capacity() << endl;
}
插入和删除:
push_back(ele);
pop_back();
insert(const_iterator pos, ele);
insert(const_iterator pos, int count, ele);
erase(const_iterator pos);
erase(const_iterator start, const_iterator end);
clear();
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(), 2, 'c');PrintVector(v1);v1.erase(v1.begin());PrintVector(v1);
}
数据存取:
at(int idx);
operator[];
front();
back();
void test01() {vector<int> v1;for (int i = 0; i < 10; i++) {v1.push_back(i);}PrintVector(v1);cout << v1.at(3) << " " << v1[8] << endl;cout << v1.front() << " " << v1.back() << endl;
}
互换容器与预留空间:
swap(vec);
reserve(int len);
void test01() {vector<int> v1, v2;v1.reserve(100000);int cnt = 0;int* p = NULL;for (int i = 0; i < 100000; i++) {v1.push_back(i);if (p != &v1[0]) {p = &v1[0];cnt++;}}cout << cnt << endl;//PrintVector(v1);//for (int i = 100; i >= 90; i--) {// v2.push_back(i);//}//PrintVector(v2);//v1.swap(v2);//PrintVector(v1);//PrintVector(v2);
}
deque容器
双端数组,可以对头端进行插入删除操作
deque与vector区别:
- deque对头部的插入删除速度快
- vector访问元素的速度快
工作原理:
deque内部有中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
构造函数:
deque<T>
deque(beg, end);
deque(n, else);
deque(const deque &deq);
void test01() {deque<int> q1;for (int i = 0; i < 10; i++) {q1.push_back(i);}Print(q1);deque<int> q2(q1.begin(), q1.end());Print(q2);deque<int> q3(10, 100);Print(q3);deque<int> q4(q3);Print(q4);
}
赋值操作:
deque& operator=(const deque &deq);
assign(beg, end);
assign(n, elem);
void test01() {deque<int> q1, q2, q3, q4;for (int i = 0; i < 10; i++) {q1.push_back(i);}Print(q1);q2 = q1;Print(q2);q3.assign(q1.begin(), q1.end());Print(q3);q4.assign(10, 100);Print(q4);
}
大小操作:
deque.empty();
deque.size();
deque.resize(num);
deque.resize(num, elem);
void test01() {deque<int> q1, q2, q3, q4;for (int i = 0; i < 10; i++) {q1.push_back(i);}Print(q1);if (q1.empty()) {cout << "空" << endl;}else {//deque没有容量的概念cout << q1.size() << endl;q1.resize(20);cout << q1.size() << endl;}
}
插入删除:
push_back(elem);
push_front(elem);
pop_back();
pop_front();
insert(pos, elem);
insert(pos, n, elem);
insert(pos, beg, end);
clear();
erase(beg, end);
erase(pos);
void test01() {deque<int> q1, q2, q3, q4;for (int i = 0; i < 10; i++) {q1.push_back(i);q2.push_front(i);}PrintDeque(q1);q1.push_front(2);PrintDeque(q1);q1.pop_front();q1.pop_back();PrintDeque(q1);q1.insert(q1.begin(), 99);PrintDeque(q1);q1.insert(q1.begin(), 10, 99);PrintDeque(q1);q1.insert(q1.begin(), q2.begin(), q2.end());PrintDeque(q1);q1.erase(q2.begin(), q2.end());PrintDeque(q1);
}
数据存取与排序:
at(int idx);
operator[];
front();
back();
sort(iterator beg, iterator end);
void test01() {deque<int> q1, q2, q3, q4;for (int i = 0; i < 10; i++) {q1.push_back(i);q1.push_back(i + 10);}PrintDeque(q1);cout << q1.at(2) << " " << q1[3] << endl;cout << q1.front() << " " << q1.back() << endl;sort(q1.begin(), q1.end());PrintDeque(q1);
}
stack容器
构造函数与赋值:
stack<T> stk;
stack(const stack &stk);
stack& operator=(const stack &stk);
数据存取与大小操作:
push(elem);
pop();
top();
empty();
size();
void test01() {stack<int> s1, s2;for (int i = 0; i < 10; i++) {s1.push(i);}s2 = s1;while (!s1.empty()) {cout << s1.top() << " " << s1.size() << endl;s1.pop();}
}
queue容器
构造函数:
queue<T> que;
queue(const queue &que);
赋值操作:
queue& operator=(const queue &que);
数据存取:
push(elem);
pop();
back();
front();
大小操作:
empty();
size();
void test01() {queue<int> q1, q2;for (int i = 0; i < 10; i++) {q1.push(i);}while (!q1.empty()) {cout << q1.front() << " " << q1.back() << " " << q1.size() << endl;q1.pop();}
}
list容器
优点:
- 动态内存分配,不会内存浪费和溢出
- 插入和删除便利,不会造成原有迭代器失效
缺点:
- 空间时间额外消耗大
构造函数:
list<T> list;
list(beg, end);
list(n, elem);
list(const list &lst);
void test01() {list<char> list1, list2;list<char> list3(10, 'c');list<char> list4(list3);
}
赋值和交换:
assign(beg, end);
assign(n, elem);
list& operator=(const list &lst);
swap(lst);
void test01() {list<char> list1, list2;list<char> list3(10, 'c');list<char> list4(list3);list1.assign(list3.begin(), list3.end());list2.assign(10, 'b');PrintList(list1);PrintList(list2);PrintList(list3);swap(list2, list3);PrintList(list2);PrintList(list3);
}
大小操作:
size();
empty();
resize(num);
resize(num, elem);
void test01() {list<int> list1, list2;for (int i = 0; i < 10; i++) {list1.push_back(i);}PrintList(list1);if (list1.empty()) {cout << "空" << endl;}else {cout << list1.size() << endl;list1.resize(20, 0);}cout << list1.size() << endl;PrintList(list1);
}
插入删除:
push_back(elem);
pop_back();
push_front(elem);
pop_front();
insert(pos, elem);
insert(pos, n, elem);
insert(pos, beg, end);
clear();
erase(beg, end);
erase(pos);
remove(elem);
void test01() {list<int> list1, list2;for (int i = 0; i < 10; i++) {list1.push_back(i);list1.push_back(19);}PrintList(list1);list1.push_front(99);list1.remove(19);PrintList(list1);list1.pop_front();list1.pop_back();PrintList(list1);list1.insert(list1.end(), 9);list1.insert(list1.end(), 9);PrintList(list1);list<int>::iterator it = list1.end();it--;list1.erase(it);PrintList(list1);
}
数据存取与反转排序:
front();
back();
reverse();
sort();
void test01() {list<int> list1, list2;for (int i = 0; i < 10; i++) {list1.push_back(i);list1.push_back(i + 10);}PrintList(list1);cout << list1.front() << " " << list1.back() << endl;list1.reverse();PrintList(list1);list1.sort();PrintList(list1);
}
set/multiset容器
本质:关联式容器,底层用二叉树实现
区别:
set
不允许有重复元素,multiset
允许
构造和赋值:
set<T> st;
set(const set &st);
set& operator=(const set &st);
void test01() {set<int> s1;set<int> s2(s1);set<int> s3 = s1;
}
大小和交换:
size();
empty();
swap(st);
void test01() {set<int> s1, s2;for (int i = 0; i < 10; i++) {s1.insert(i);s2.insert(i + 10);}PrintSet(s1);PrintSet(s2);if (s1.empty()) {cout << "空" << endl;}else {cout << s1.size() << endl;}s1.swap(s2);PrintSet(s1);PrintSet(s2);
}
插入删除:
insert(elem);
clear();
erase(pos);
erase(beg, end);
erase(elem);
void test01() {set<int> s1, s2;for (int i = 0; i < 10; i++) {s1.insert(i);s2.insert(i + 10);}PrintSet(s1);PrintSet(s2);s2.erase(19);PrintSet(s2);
}
查找统计:
find(key);
count(key);
void test01() {set<int> s1, s2;for (int i = 0; i < 10; i++) {s1.insert(i);s2.insert(i + 10);}PrintSet(s1);PrintSet(s2);set<int>::iterator it = s1.find(6);cout << *it << endl;if (s1.find(90) != s1.end()) {cout << "找到90" << endl;}else {cout << "找不到90" << endl;}cout << s1.count(15) << " " << s2.count(15) << endl;
}
pair对组创建:
pair<type, type> p (v1, v2);
pair<type, type> p = make_pair (v1, v2);
void test01() {pair<string, int> p1("Tom", 11);cout << p1.first << " " << p1.second << endl;pair<string, int> p2 = make_pair("Steve", 18);cout << p2.first << " " << p2.second << endl;
}
排序:
- 默认排序规则为从小到大
class MyCompare {
public:bool operator()(int v1, int v2)const {return v1 > v2;}
};void test01() {set<int> s1, s2;s1.insert(10);s1.insert(40);s1.insert(20);s1.insert(90);PrintSet(s1);set<int, MyCompare> s3;s3.insert(10);s3.insert(40);s3.insert(20);s3.insert(90);for (set<int, MyCompare>::iterator it = s3.begin(); it != s3.end(); it++) {cout << (*it) << " ";}cout << endl;
}
map/multimap容器
简介:
- 所有元素都是pair
- 第一个元素为key,第二个元素是value
- 根据value自动排序
本质:
- 关联式容器,底层用二叉树实现
区别:
- map不允许重复key值元素
- multimap允许重复key元素
构造赋值:
map<T1, T2> mp;
map(const map &mp);
map& operator=(const map &mp);
void test01() {map<int, char> m1;map<int, char> m2(m1);map<int, char> m3 = m2;
}
大小交换:
size();
empty();
swap(st);
void test01() {map<int, char> m1, m2;m1.insert(pair<int, char>(1, 'a'));m1.insert(pair<int, char>(2, 'c'));m1.insert(pair<int, char>(3, 'b'));if (m1.empty()) {cout << "空" << endl;}else {PrintMap(m1);cout << m1.size() << endl;}m2.insert(pair<int, char>(1, 'p'));m2.insert(pair<int, char>(2, 'm'));m2.insert(pair<int, char>(3, 'n'));m1.swap(m2);PrintMap(m1);PrintMap(m2);
}
插入删除:
insert(elem);
clear();
erase(pos);
erase(beg, end);
erase(key);
void test01() {map<int, char> m1, m2;m1.insert(pair<int, char>(1, 'a'));m1.insert(pair<int, char>(2, 'c'));m1.insert(pair<int, char>(3, 'b'));m2.insert(pair<int, char>(1, 'p'));m2.insert(pair<int, char>(2, 'm'));m2.insert(pair<int, char>(3, 'n'));PrintMap(m2);m2.erase(2);PrintMap(m2);m2.erase(m2.begin());PrintMap(m2);
}
查找统计:
find(key);
count(key);
void test01() {map<int, char> m1, m2;m2.insert(pair<int, char>(1, 'p'));m2.insert(pair<int, char>(2, 'm'));m2.insert(pair<int, char>(3, 'n'));m2.insert(pair<int, char>(4, 'p'));PrintMap(m2);map<int, char>::iterator pos = m2.find(2);cout << (*pos).first << " " << (*pos).second << endl;cout << m2.count(1) << endl;
}
排序:
void test01() {map<int, int> m1, m2;m2.insert(pair<int, int>(1, 10));m2.insert(pair<int, int>(2, 30));m2.insert(pair<int, int>(3, 20));m2.insert(pair<int, int>(4, 40));PrintMap(m2);map<int, int, MyCompare> m3;m3.insert(pair<int, int>(1, 10));m3.insert(pair<int, int>(2, 30));m3.insert(pair<int, int>(3, 20));m3.insert(pair<int, int>(4, 40));for (map<int, int, MyCompare>::iterator it = m3.begin(); it != m3.end(); it++) {cout << (*it).second << " ";}cout << endl;
}
函数对象
概念:
- 重载函数调用操作符的类,其对象称为函数对象
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:
函数对象(仿函数)是一个类,不是一个函数
特点:
- 可以像普通函数一样使用
- 可以有自己的状态
- 可以作为参数传递
class MyAdd {
public:int operator()(int v1, int v2) {return v1 + v2;}
};class MyPrint {
public:MyPrint() {this->cnt = 0;}void operator()(string test) {cout << test << endl;this->cnt++;}int cnt;
};void doPrint(MyPrint p, string text) {
}void test01() {MyAdd m;cout << m(10, 11) << endl;MyPrint p;p("hello");p("hello");p("hello");cout << p.cnt << endl;doPrint(p, "helloo");
}
谓词:
- 返回bool类型的仿函数称为谓词
- 如果operator()接受一个参数,那么叫做一元谓词
- 如果operator()接受两个参数,那么叫做二元谓词
class JudgeFour {
public:bool operator()(int v) {return v > 4;}
};void test01() {vector<int> v;for (int i = 0; i < 6; i++) {v.push_back(i);}vector<int>::iterator it = find_if(v.begin(), v.end(), JudgeFour());if (it == v.end()) {cout << "没找到" << endl;}else {cout << *it << endl;}
}
class JudgeFour {
public:bool operator()(int v1, int v2) {return v1 > v2;}
};void test01() {vector<int> v;for (int i = 0; i < 6; i++) {v.push_back(i);}for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;sort(v.begin(), v.end(), JudgeFour());for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}
内建函数对象:
分类:
- 算术仿函数
- 关系仿函数
- 逻辑仿函数
用法:
- 这些仿函数所产生的对象,用法和一般函数完全相同
- 引入头文件
#include<functional>
算术仿函数:
template<class T> T plus<T>
加法template<class T> T minus<T>
减法template<class T> T multiplies<T>
乘法template<class T> T divides<T>
除法template<class T> T modulus<T>
取模template<class T> T negate<T>
取反
void test01() {plus<int> p;cout << p(10, 20) << endl;minus<int> mi;cout << mi(30, 20) << endl;multiplies<int> mu;cout << mu(2, 90) << endl;divides<int> d;cout << d(90, 2) << endl;modulus<int> mo;cout << mo(99, 2) << endl;negate<int> n;cout << n(9) << endl;
}
关系仿函数:
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>
小于等于
void test01() {vector<int> v;v.push_back(10);v.push_back(70);v.push_back(30);v.push_back(40);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 << " ";}cout << endl;
}
逻辑仿函数:
template<class T> bool logical_and<T>
与template<class T> bool logical_or<T>
或template<class T> bool logical_not<T>
非
void test01() {vector<bool> v;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 << " ";}cout << endl;vector<bool> c;c.resize(v.size());transform(v.begin(), v.end(), c.begin(), logical_not<bool>());for (vector<bool>::iterator it = c.begin(); it != c.end(); it++) {cout << *it << " ";}
}
遍历算法
for_each:
for_each(iterator beg, iterator end, _func);
void print01(int v) {cout << v << " ";
}class print02 {
public:void operator()(int v) {cout << v << " ";}
};void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i);}for_each(v.begin(), v.end(), print01);cout << endl;for_each(v.begin(), v.end(), print02());
}
transform:
拷贝到另一个容器
transform(iterator beg1, iterator end1, iterator beg2, _func)
void print01(int v) {cout << v << " ";
}class Transform {
public:int operator()(int v) {return v;}
};void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i);}for_each(v.begin(), v.end(), print01);cout << endl;vector<int> c;c.resize(v.size());transform(v.begin(), v.end(), c.begin(), Transform());for_each(c.begin(), c.end(), print01);cout << endl;
}
查找算法
函数原型:
find(iterator beg, iterator end, value);
查找返回下标find_if(iterator beg, iterator end, _Pred);
条件查找adjacent_find(iterator beg, iterator end);
查找相邻重复元素bool binary_search(iterator beg, iterator end, value);
二分查找count(iterator beg, iterator end, value)
统计元素出现次数count_if(iterator beg, iterator end, _Pred)
条件统计
void MyPrint(vector<int> v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}class GreaterFive {
public:int operator()(int v) {return v > 5;}
};void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i);if (i > 7) {v.push_back(7);v.push_back(7);}}MyPrint(v);vector<int>::iterator it1 = find(v.begin(), v.end(), 9);cout << *it1 << endl;vector<int>::iterator it2 = find_if(v.begin(), v.end(), GreaterFive());cout << *it2 << endl;vector<int>::iterator it3 = adjacent_find(v.begin(), v.end());cout << *it3 << endl;bool ans = binary_search(v.begin(), v.end(), 7);cout << ans << endl;int res = count(v.begin(), v.end(), 7);cout << res << endl;int cnt = count_if(v.begin(), v.end(), GreaterFive());cout << cnt << endl;
}
排序算法
函数原型:
sort(iterator beg, iterator end, _Pred)
排序random_shuffle(iterator beg, iterator end)
随机排序merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
合并两个容器 存储到另一个容器reverse(iterator beg, iterator end)
反转
void MyPrint(vector<int> v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}void Print(int v) {cout << v << " ";
}void test01() {vector<int> v;for (int i = 0; i < 10; i++) {v.push_back(i);}MyPrint(v);sort(v.begin(), v.end(), MySort());MyPrint(v);random_shuffle(v.begin(), v.end());MyPrint(v);
}void test02() {vector<int> v, c;for (int i = 0; i < 10; i++) {v.push_back(i);c.push_back(i + 10);}vector<int> target;target.resize(v.size() + c.size());merge(v.begin(), v.end(), c.begin(), c.end(), target.begin());for_each(target.begin(), target.end(), Print);cout << endl;reverse(target.begin(), target.end());MyPrint(target);
}
拷贝替换算法
函数原型:
copy(iterator beg, iterator end, iterator dest)
拷贝到另一个容器replace(iterator beg, iterator end, oldvalue, newvalue)
指定范围内更换元素replace(iterator beg, iterator end, _pred, newvalue)
条件替换swap(container c1, container c2)
互换两个容器的元素
void MyPrint(vector<int> v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}void Print(int v) {cout << v << " ";
}class MyWeici {
public:int operator()(int v1) {return v1 > 5;}
};void test02() {vector<int> v, c;for (int i = 0; i < 10; i++) {v.push_back(i);}MyPrint(v);vector<int> target;target.resize(v.size());copy(v.begin(), v.end(), target.begin());MyPrint(target);replace(target.begin(), target.end(), 6, 99);MyPrint(target);replace_if(target.begin(), target.end(), MyWeici(), 99);MyPrint(target);swap(v, target);MyPrint(v);MyPrint(target);
}
算术生成算法
函数原型:
accumulate(iterator beg, iterator end, value)
计算容器元素和fill(iterator beg, iterator end, value)
向容器中填充指定元素
void test02() {vector<int> v, c;for (int i = 0; i < 10; i++) {v.push_back(i);}MyPrint(v);int sum = accumulate(v.begin(), v.end(), 0);cout << sum << endl;c.resize(20);fill(c.begin(), c.end(), 100);MyPrint(c);
}
集合算法
函数原型:
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
交集set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
并集set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
差集
void test02() {vector<int> v, c;for (int i = 0; i < 10; i++) {v.push_back(i);c.push_back(i + 5);}MyPrint(v);MyPrint(c);vector<int> target;//target.resize(min(v.size(), c.size()));//set_intersection(v.begin(), v.end(), c.begin(), c.end(), target.begin());//target.resize(v.size() + c.size());//set_union(v.begin(), v.end(), c.begin(), c.end(), target.begin());target.resize(max(v.size(), c.size()));set_difference(v.begin(), v.end(), c.begin(), c.end(), target.begin());MyPrint(target);
}