品牌开发公司排名/知了seo
参考资源:1 黑马程序员
参考资源:2 《C++标准库 - 侯捷》中的 5.2 节-容器
文章目录
- 1 各容器的特点总结及使用场景
- 2 各个容器的使用场景
- 3 函数对象
- 3.1 函数对象的基本概念
- 3.2 函数对象实例演示+解释
- 3.3 函数对象的优势
- 4 谓词
- 4.1 谓词的基本概念
- 4.2 一元谓词实例使用
- 4.2 二元谓词实例使用
- 5 内建函数对象
- 5.1 内建函数的基本概念
- 5.2 内建函数分类
- 6 函数对象适配器
- 6.1 函数对象适配器的基本概念
- 6.2 bind1st 和 bind2nd绑定配置器的实例使用
- 6.2.1 bind1st和bin2nd的区别
- 6.3 not1和not2取反配置器的实例使用
- 6.4 ptr_func 函数指针适配器
- 6.5 mem_fun mem_func_ref 成员函数适配器
- 6.6函数配置器使用总结
- 7 算法
- 7.1 常用遍历算法
- 7.2 常用查找算法
- 7.3 常用排序算法
- 7.4 常用拷贝和替换算法
1 各容器的特点总结及使用场景
- vector 头部与中间插入和删除效率较低,在尾部插入和删除效率高,支持随机访问。
- deque 是在头部和尾部插入和删除效率较高,支持随机访问,但效率没有 vector 高。
- list 在任意位置的插入和删除效率都较高,但不支持随机访问。
- set 由红黑树实现,其内部元素依据其值自动排序,每个元素值只能出现一次,不允许重复,且插入和删除效率比用其他序列容器高。
- map 可以自动建立 Key - value 的对应,key 和 value 可以是任意你需要的类型,根据 key 快速查找记录。
2 各个容器的使用场景
- 如果需要高效的随机存取,不在乎插入和删除的效率,使用 vector。
- 如果需要大量的插入和删除元素,不关心随机存取的效率,使用 list。
- 如果需要随机存取,并且关心两端数据的插入和删除效率,使用 deque。
- 如果打算存储数据字典,并且要求方便地根据 key 找到 value,一对一的情况使用 map,一对多的情况使用 multimap。
- 如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用 set,不唯一存在的情况使用 multiset。
3 函数对象
3.1 函数对象的基本概念
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。
注意:
- 函数对象(仿函数)是一个类,不是一个函数。
- 函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
3.2 函数对象实例演示+解释
不难看出下面代码用了两种方式去实现记录函数调用次数,
- 方法一:全局变量,但是这种方式可能带来的是1 无意间的修改2干扰了模块化3 并发(Concurrency)的问题…等等问题
- 方法二:我们用函数对象 ,内部定义一个num的成员。避免的这一问题。利用了
函数对象可以保存函数调用的状态
的特性。补充:这边用到的是struct 而不是 class 。并不是不能用class,只是为了方便,class和struct的区别只是在于
struct默认为public
。
//全局变量
int num = 0;
//函数对象重载了()
struct MyPrint
{MyPrint(){num = 0;}void operator()(int val){num++;cout << val << endl;}int num;
};
//普通函数 用来测试比对
void MyPrint1(int val)
{num++;cout<<val<<endl;
}int main(void)
{MyPrint prin1;//常见一个实例类prin1(10);prin1(20);prin1(30);cout << prin1.num<<endl;cout<<"----分割线----"<<endl;MyPrint1(10);MyPrint1(20);MyPrint1(30);cout << num << endl; return 0;
}
3.3 函数对象的优势
-
函数对象可以像普通函数一样调用。
-
函数对象可以像函数那样接受参数。
-
函数对象 超出函数的概念 函数对象可以保存函数调用的状态。
-
函数对象课可内联编译,性能好。用函数指针几乎不可能。
-
模板函数对象具有通用性,优势之一。
4 谓词
4.1 谓词的基本概念
谓词是指普通函数或 重载的operator() 返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式.
4.2 一元谓词实例使用
前提说明:
- find_if是一个模板函数,接受两个数据类型:InputItearator迭代器,Predicate用于比较数值的函数或者函数对象(仿函数)。查询成功返回对应元素的迭代器,查询失败返回v.end();(最后的迭代器)
// 函数对象
struct compare
{bool operator()(int val){return val > 5;}
};void test101()
{vector<int> v;v.push_back(1);v.push_back(4);v.push_back(7);v.push_back(11);vector<int>::iterator var = find_if(v.begin(), v.end(), compare());//第三个参数这边用的是匿名函数对象if (var == v.end()){cout << "查询失败"<< endl;}else{cout << "找到了" <<"当前值:"<<*var<<endl;}
}
4.2 二元谓词实例使用
前提说明:sort 是排序算法 参数一 和 参数二 通过迭代器指定排序区间,参数三可以用函数对象改变算法策略。
struct MyCompare1
{bool operator()(int val, int val1){return val > val1;}
};void test111()
{vector<int > v;v.push_back(10);v.push_back(1);v.push_back(30);v.push_back(13);//利用函数对象 改变算法策略 原本是默认从小到大sort(v.begin(), v.end(), MyCompare1());//匿名函数对象for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout<<*it<<endl;}}
写法二,不用匿名函数对象 直接使用实例对象
struct MyCompare1
{bool operator()(int val, int val1){return val > val1;}
};void test111()
{vector<int > v;v.push_back(10);v.push_back(1);v.push_back(30);v.push_back(13);MyCompare1 m1;//创建实例函数对象//利用函数对象 改变算法策略 原本是默认从小到大sort(v.begin(), v.end(), m1);//使用实例函数对象for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout<<*it<<endl;}
}
5 内建函数对象
5.1 内建函数的基本概念
STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件#include<functional>
.
类名<参数类型> 实例类名;
5.2 内建函数分类
6个算数类函数对象,除了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>//取反仿函数
6个关系运算类函数对象,每一种都是二元运算。
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>//小于等于
逻辑运算类运算函数,not为一元运算,其余为二元运算
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
plus<int> p;//相加
int a=p(10, 20);
cout << a<<endl;equal_to<string> e;//判断是否等于 返回 bool
bool e1=e("aaa", "bbb");
cout << e1<<endl;
6 函数对象适配器
6.1 函数对象适配器的基本概念
函数对象适配器是完成一些配接工作,这些工作包括绑定(bind),否定(negate),以及对一般成员或成员函数的修饰,使其成为函数对象。重点掌握以下四种重要的以及三种不常用的。
6.2 bind1st 和 bind2nd绑定配置器的实例使用
需求分析: 在遍历容器的时候,我希望将容器中的值全部加上x(我们设定的增值)之后显示出来。
问题分析:从for_each的定义可以看出,第三个参数位置的函数对象每次只能传入一个参数,如果要使用for_each去直接实现需求显然是不可能的。
适配器作用:利用bind1st 或者bind2nd适配器将二元函数对象转成一元函数对象
( )。
class MyPrint :public binary_function<int, int, void>
{
public:void operator()(int a, int b) const{cout <<"和为:"<< a + b <<" 第一个值为:"<<a<<" 第二个值为:"<<b<< endl;}
};
void test01()
{vector<int> v;for (int i = 0; i < 5; i++){v.push_back(i);}int x=100;for_each(v.begin(), v.end(), bind1st( MyPrint(),x ));
}
class MyPrint :public binary_function<int, int, void>
{
public:void operator()(int a, int b) const{cout <<"和为:"<< a + b <<" 第一个值为:"<<a<<" 第二个值为:"<<b<< endl;}
};void test01()
{vector<int> v;for (int i = 0; i < 5; i++){v.push_back(i);}int x=100;for_each(v.begin(), v.end(), bind2nd( MyPrint(),x ));
}
6.2.1 bind1st和bin2nd的区别
bind1st,将addnum绑定为函数对象的第一个参数
bin2nd,将addnum绑定为函数对象的第二个参数
6.3 not1和not2取反配置器的实例使用
not1作用:对一元函数对象取反 。从输出大于5的第一个值转变成 小于5的第一个值
class MyGreater:public unary_function<int, bool>
{
public:bool operator()(int val)const{return val > 5;}};void test909()
{vector<int> v;v.push_back(1);v.push_back(3);v.push_back(10);v.push_back(2);vector<int>::iterator it = find_if(v.begin(),v.end(), not1(MyGreater()));cout<<*it<<endl;}
not2作用:对二元函数对象取反 。从大到小排序,设置成从小到大排序
class Compare1:public binary_function<int, int, void>
{
public:bool operator()(int val,int val1)const{return val > val1;}
};void test111()
{vector<int> v;v.push_back(1);v.push_back(78);v.push_back(10);v.push_back(2);sort(v.begin(),v.end(),not2(Compare1()));for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout<<(*it)<<endl;}}
6.4 ptr_func 函数指针适配器
//如何给一个普通函数使用绑定适配器(bind1st bind2nd)绑定一个参数?(拓展)
//ptr_fun
void myprint04(int v1, int v2){cout << v1 + v2 << " ";
}
void test04(){vector<int> v;v.push_back(2);v.push_back(1);v.push_back(5);v.push_back(4);//1 将普通函数适配成函数对象//2 然后通过绑定器绑定参数for_each(v.begin(), v.end(), bind2nd(ptr_fun(myprint04), 100));cout << endl;//总结: ptr_fun 将普通函数转变为函数对象
}
6.5 mem_fun mem_func_ref 成员函数适配器
//mem_fun mem_fun_ref
//如果我们容器中存储的是对象或者对象指针,如果能指定某个成员函数处理成员数据。
class student{
public:student(string name, int age) :name(name), age(age){}void print(){cout << "name:" << name << " age:" << age << endl;;}void print2(int a){cout << "name:" << name << " age:" << age << " a:" << a << endl;}int age;string name;
};void test05(){//mem_fun : 如果存储的是对象指针,需要使用mem_funvector<student*> v;student* s1 = new student("zhaosi", 10);student* s2 = new student("liuneng", 20);student* s3 = new student("shenyang", 30);student* s4 = new student("xiaobao", 40);v.push_back(s1);v.push_back(s2);v.push_back(s3);v.push_back(s4);for_each(v.begin(), v.end(), mem_fun(&student::print));cout << "-----------------------------" << endl;//mem_fun_ref : 如果容器中存储的是对象,需要使用mem_fun_refvector<student> v2;v2.push_back(student("zhaosi", 50));v2.push_back(student("liuneng", 60));v2.push_back(student("shenyang", 70));v2.push_back(student("xiaobao", 80));for_each(v2.begin(), v2.end(), mem_fun_ref(&student::print));}
6.6函数配置器使用总结
- 需要继承一个类 :
binary_function< >
二元函数对象使用;unary_function<>
一元函数使用。例如 :public binary_function < int int bool >
前两个表示传入参数的类型 第三个表示返回的类型。 - 需要加上
const
限定符 例如:bool operator(int a,int b)const
operator
名称不要写错,不好找。
7 算法
这部分具体使用具体查询。内容过多,不一一列举。
7.1 常用遍历算法
for_each 和 transform用法简单。唯一需要注意的就是利用transform把一个容器元素搬到另外一个容器,需要预先开辟空间。不能是
reserve
而是使用resize
如下
Target.resize(Source.size());
/*遍历算法 遍历容器元素@param beg 开始迭代器@param end 结束迭代器@param _callback 函数回调或者函数对象@return 函数对象
*/
for_each(iterator beg, iterator end, _callback);
/*transform算法 将指定容器区间元素搬运到另一容器中注意 : transform 不会给目标容器分配内存,所以需要我们提前分配好内存@param beg1 源容器开始迭代器@param end1 源容器结束迭代器@param beg2 目标容器开始迭代器@param _cakkback 回调函数或者函数对象@return 返回目标容器迭代器
*/
transform(iterator beg1, iterator end1, iterator beg2, _callbakc)for_each:
/*template<class _InIt,class _Fn1> inline
void for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{for (; _First != _Last; ++_First)_Func(*_First);
}*///for_each 和 transform用法简单 唯一注意的就是
7.2 常用查找算法
/*find算法 查找元素@param beg 容器开始迭代器@param end 容器结束迭代器@param value 查找的元素@return 返回查找元素的位置
*/
find(iterator beg, iterator end, value)
/*find_if算法 条件查找@param beg 容器开始迭代器@param end 容器结束迭代器@param callback 回调函数或者谓词(返回bool类型的函数对象)@return bool 查找返回true 否则false
*/
find_if(iterator beg, iterator end, _callback);/*adjacent_find算法 查找相邻重复元素@param beg 容器开始迭代器@param end 容器结束迭代器@param _callback 回调函数或者谓词(返回bool类型的函数对象)@return 返回相邻元素的第一个位置的迭代器
*/
adjacent_find(iterator beg, iterator end, _callback);
/*binary_search算法 二分查找法注意: 在无序序列中不可用@param beg 容器开始迭代器@param end 容器结束迭代器@param value 查找的元素@return bool 查找返回true 否则false
*/
bool binary_search(iterator beg, iterator end, value);
/*count算法 统计元素出现次数@param beg 容器开始迭代器@param end 容器结束迭代器@param value回调函数或者谓词(返回bool类型的函数对象)@return int返回元素个数
*/
count(iterator beg, iterator end, value);
/*count算法 统计元素出现次数@param beg 容器开始迭代器@param end 容器结束迭代器@param callback 回调函数或者谓词(返回bool类型的函数对象)@return int返回元素个数
*/
count_if(iterator beg, iterator end, _callback);
7.3 常用排序算法
/*merge算法 容器元素合并,并存储到另一容器中@param beg1 容器1开始迭代器@param end1 容器1结束迭代器@param beg2 容器2开始迭代器@param end2 容器2结束迭代器@param dest 目标容器开始迭代器
*/
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
/*sort算法 容器元素排序注意:两个容器必须是有序的@param beg 容器1开始迭代器@param end 容器1结束迭代器@param _callback 回调函数或者谓词(返回bool类型的函数对象)
*/
sort(iterator beg, iterator end, _callback)
/*sort算法 对指定范围内的元素随机调整次序@param beg 容器开始迭代器@param end 容器结束迭代器
*/
random_shuffle(iterator beg, iterator end)
/*reverse算法 反转指定范围的元素@param beg 容器开始迭代器@param end 容器结束迭代器
*/
reverse(iterator beg, iterator end)
7.4 常用拷贝和替换算法
/*copy算法 将容器内指定范围的元素拷贝到另一容器中@param beg 容器开始迭代器@param end 容器结束迭代器@param dest 目标起始迭代器
*/
copy(iterator beg, iterator end, iterator dest)
/*replace算法 将容器内指定范围的旧元素修改为新元素@param beg 容器开始迭代器@param end 容器结束迭代器@param oldvalue 旧元素@param oldvalue 新元素
*/
replace(iterator beg, iterator end, oldvalue, newvalue)
/*replace_if算法 将容器内指定范围满足条件的元素替换为新元素@param beg 容器开始迭代器@param end 容器结束迭代器@param callback函数回调或者谓词(返回Bool类型的函数对象)@param oldvalue 新元素
*/
replace_if(iterator beg, iterator end, _callback, newvalue)
/*swap算法 互换两个容器的元素@param c1容器1@param c2容器2
*/
swap(container c1, container c2)
学习笔记总结,如有错误,欢迎指出!。