3.9 STL容器使用时机
|
vector |
deque |
list |
set |
multiset |
map |
multimap |
典型内存结构 |
单端数组 |
双端数组 |
双向链表 |
二叉树 |
二叉树 |
二叉树 |
二叉树 |
可随机存取 |
是 |
是 |
否 |
否 |
否 |
对key而言:不是 |
否 |
元素搜寻速度 |
慢 |
慢 |
非常慢 |
快 |
快 |
对key而言:快 |
对key而言:快 |
元素安插移除 |
尾端 |
头尾两端 |
任何位置 |
- |
- |
- |
- |
- vector的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
- deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。
vector与deque的比较:
一:vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置 却是不固定的。
二:如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关。
三:deque支持头部的快速插入与快速移除,这是deque的优点。
- list的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
- set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
- map的使用场景:比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。
4. 常用算法
4.1 函数对象
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
分类:假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
函数对象的作用主要是什么?STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。
//函数对象是重载了函数调用符号的类 class MyPrint { public: MyPrint() { m_Num = 0; } int m_Num;
public: void operator() (int num) { cout << num << endl; m_Num++; } };
//函数对象 //重载了()操作符的类实例化的对象,可以像普通函数那样调用,可以有参数 ,可以有返回值 void test01() { MyPrint myPrint; myPrint(20);
} // 函数对象超出了普通函数的概念,可以保存函数的调用状态 void test02() { MyPrint myPrint; myPrint(20); myPrint(20); myPrint(20); cout << myPrint.m_Num << endl; }
void doBusiness(MyPrint print,int num) { print(num); }
//函数对象作为参数 void test03() { //参数1:匿名函数对象 doBusiness(MyPrint(),30); }
|
总结:
1、函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。
2、函数对象超出普通函数的概念,函数对象可以有自己的状态
3、函数对象可内联编译,性能好。用函数指针几乎不可能
4、模版函数对象使函数对象具有通用性,这也是它的优势之一
11 仿函数 函数对象(仿函数)
重载() 所以函数的对象 使用()像函数调用
是类 而不是普通的函数
内部记录状态
作为类型 与模板进行配合
#include <iostream>
using namespace std;
class MyPrint{
public:
void operator()(int num){
cout<<"num="<<num<<endl;
count++;//统计调用了多少次仿函数
}
int count=0;
};
void MyPrint2(int num){
cout<<"num="<<num<<endl;
}
void test01(){
//MyPrint是一个类 而不是函数
MyPrint myprint;
myprint(111);//看起来像函数调用,仿的形式上的东西
//MyPrint2(222);//实际的函数
MyPrint()(1000);//匿名对象的形式调用
}
//函数对象已经超出了普通函数的概念,内部可以保存状态
//有点像其他语言的闭包
void test02(){
MyPrint myprint;
myprint(111);
myprint(111);
myprint(111);
myprint(111);
myprint(111);
cout<<"myprint使用次数:"<<myprint.count<<endl;
//一个类中可以用仿函数记录属性
}
//函数对象作为参数
void doPrint(MyPrint print,int num){
print(num);
}
void test03(){
doPrint(MyPrint(),20);
// set<int,MyPrint>s;
}
int main(){
// test01();
// test02();
test03();
return 0;
}
4.2 谓词
谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。
class GreaterThenFive { public: bool operator()(int num) { return num > 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(), GreaterThenFive()); if (it == v.end()) { cout << "没有找到" << endl; } else { cout << "找到了: " << *it << endl; } }
//二元谓词 class MyCompare { public: bool operator()(int num1, int num2) { return num1 > num2; } };
void test02() { vector<int> v; v.push_back(10); v.push_back(40); v.push_back(20); v.push_back(90); v.push_back(60);
//默认从小到大 sort(v.begin(), v.end()); for (vector<int>::iterator it = v.begin(); it != v.end();it++) { cout << *it << " "; } cout << endl; cout << "----------------------------" << endl; //使用函数对象改变算法策略,排序从大到小 sort(v.begin(), v.end(),MyCompare()); for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } |
12 谓词
重载() 返回值是bool类型
普通函数或者仿函数 返回值为bool类型
一元 一个参数 二元 两个参数
一元查找大于20的数字 find_if 返回迭代器
二元排序 借助lambda 或回调函数
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class GreaterThan20{
public:
bool operator()(int value){
return value>20;
}
};
//一元谓词
//一元体现在在有一个参数 谓词体现在 返回值为bool类型
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);
v.push_back(60);
//查找第一个大于20的数字
// GreaterThan20 greaterThan;
// find_if(v.begin(),v.end(),greaterThan);//第三个参数是函数对象 匿名对象可以
vector<int>::iterator pos=find_if(v.begin(),v.end(), GreaterThan20());//返回一个迭代器 找不到返回end位置
if(pos!=v.end()){
cout<<"找到大于20的数"<<*pos<<endl;
}else{
cout<<"未找到"<<endl;
}
}
class MyCompare{
public:
bool operator()(int v1,int v2){
return v1>v2;
}
};
bool MYCOM(int v1, int v2){
return v1>v2;
}
//二元谓词
void test02(){
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
v.push_back(60);
// sort(v.begin(),v.end(),MYCOM);
sort(v.begin(),v.end(),MyCompare());
for_each(v.begin(),v.end(),[](int value){ cout<<value<<endl;});//也可以写一个回调函数
//匿名函数 lambda表达式 [](){}..[]标识符.():参数列表.{}函数体
}
int main(){
//test01();
test02();
return 0;
}
(本笔记内容整理自网络资源,侵删)