C++进阶 STL(2) 第二天 一元/二元函数对象、一元/二元谓词、stack容器、queue容器、list容器(双向链表)、set容器、对组、map容器
01 上次课程回顾
昨天讲了三个容器
string string是对char*进行的封装
vector 单口容器 动态数组
deque(双端队列)
函数对象/谓词:
一元函数对象:
for_each:
谓词: predicate
一元谓词:
find_if
二元函数对象: transform
transform操作: 两个容器相加 放到第三个
class myplus {
public:
int operator()(int v1,int v2){
return v1 + v2;
}
private:
};
void test03() {
vector<int> v1,v2,v3;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i+1);
}
/*
template<class _InIt1,
class _InIt2,
class _OutIt,
class _Fn> inline
_OutIt transform(const _InIt1 _First1, const _InIt1 _Last1,
const _InIt2 _First2, _OutIt _Dest, _Fn _Func)
{ // transform [_First1, _Last1) and [_First2, ...) with _Func
_Adl_verify_range(_First1, _Last1);
auto _UFirst1 = _Get_unwrapped(_First1);
const auto _ULast1 = _Get_unwrapped(_Last1);
const auto _Count = _Idl_distance<_InIt1>(_UFirst1, _ULast1);
auto _UFirst2 = _Get_unwrapped_n(_First2, _Count);
auto _UDest = _Get_unwrapped_n(_Dest, _Count);
for (; _UFirst1 != _ULast1; ++_UFirst1, (void)++_UFirst2, ++_UDest)
{
*_UDest = _Func(*_UFirst1, *_UFirst2); ←!最后的处理,这里是二元函数对象
}
_Seek_wrapped(_Dest, _UDest);
return (_Dest);
}
v1+v2 放到v3的开始位置
*/
v3.resize(v1.size());
for_each(v1.begin(), v1.end(), print2);
cout << endl;
for_each(v2.begin(), v2.end(), print2);
cout << endl;
for_each(v3.begin(), v3.end(), print2);
cout << endl;
transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), myplus()); // 匿名函数对象
cout << "--------------" << endl;
for_each(v1.begin(), v1.end(), print2);
cout << endl;
for_each(v2.begin(), v2.end(), print2);
cout << endl;
for_each(v3.begin(), v3.end(), print2);
cout << endl;
}
二元谓词:
class mycompare04 {
public:
bool operator()(int v1,int v2) {
return v1 > v2; // 从大到小排序
}
};
// 二元谓词 应用举例: sort
void test04()
{
vector<int> v;
v.push_back(5);
v.push_back(2);
v.push_back(7);
v.push_back(9);
/*
template<class _RanIt,
class _Pr> inline
void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred)
{ // order [_First, _Last), using _Pred
_Adl_verify_range(_First, _Last);
const auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred));
}
*/
sort(v.begin(), v.end(),mycompare04());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++ )
{
cout << *it << endl;
}
}
02 stack容器课堂练习
03 queue容器课堂练习
04list容器概念
STL中的list是双向链表
一个节点有两个指针
05 list容器基本操作
mylist.sort(); // 默认从小到大
传入函数对象或者函数指针让他从大到小
对于对象的排序要指定排序方法。
示例:
06 set集合概念
二叉树:
一个节点 每个节点最多有两个子节点
二叉搜索树:
左子树都比父节点小
右子树都比父节点大
这个就叫二叉搜索树
有可能出现左边深度很高 右边深度没那么高的清空
平衡二叉搜索树(平衡二叉树)(尽量保证左子树和右子树深度一样):
红黑树是平衡二叉树的一种 也是达到上面的效果
set容器:
内部是树,自动形成平衡二叉搜索树的机制,
以平衡二叉树(红黑树)为底层实现机制
set容器元素唯一
multiset可以插入重复元素
07 set初始化_插入和删除_find查找
功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置.
注意:如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!
功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
注意:返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置。同样,如果val大于数组中全部元素,返回的是last。(注意:数组下标越界)
equal_range返回的是一个pair
pair.first 是lower_bound
pair.second 是 upper_bound
从大到小排序:
方法一:
方法二:
其实内部就是等价于这个:
实现对特定类的排序:
multiset:
08 上午课程回顾
栈和队列没提供迭代器 因为内部有自己的实现规则
09 对组
10 map集合概念和四种插入方式区别
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <map>
#include <string>
using namespace std;
// map容器初始化
void test01()
{
// map容器的模板参数 需要制定key类型 value类型
map<int, string> mymap; // 默认构造
map<int, string> mymap2(mymap); // 拷贝构造
}
// map插入操作
void test02() {
map<int, int> mymap;
// 第一种插入方式
//pair<int, int> mypair(1, 5);
//mymap.insert(mypair);
mymap.insert(pair<int,int>(1,5));
// 第二种
pair<map<int,int>::iterator,bool> ret = mymap.insert(make_pair(2,10));
if (ret.second) {
cout << "插入成功" << endl;
}
else {
cout << "插入失败" << endl;
}
// 第三种
mymap.insert(map<int, int>::value_type(3, 15));
// 第四种
mymap[4] = 20;
mymap[2] = 100; // 如果key存在,会修改容器指定key元素的值
// 如果你访问的key不存在,他会帮你把这个数据插入进去
pair<map<int, int>::iterator, bool> ret2 = mymap.insert(map<int, int>::value_type(2, 210)); // 不能再插入了 已经有2这个key了
if (ret2.second) {
cout << "插入成功" << endl;
}
else {
cout << "插入失败" << endl;
}
for (map<int, int>::iterator it = mymap.begin(); it != mymap.end(); it++)
{
cout << "key:" << it->first << " value:" << it->second << endl;
}
cout << endl;
}
int main(void)
{
test02();
return 0;
}
12 multimap课堂案例
/*
公司今天照片了5个员工
5个员工进入公司之后 需要指派员工在哪个部门工作
人员信息有:姓名 年龄 电话 工资等组成
通过Multimap进行信息的插入 保存 显示
分部门显示员工信息 显示全部员工信息
*/
#include <iostream>
#include <vector>
#include <map>
using namespace std;
/*
公司今天入职了5个员工
5个员工进入公司之后需要指派员工在哪个部门工作
人员信息有:姓名年龄电话工资等组成
通过multimap进行信息的插入保存显示
分部门显示员工信息显示全部员工信息
*/
#define SALE_DEPARTMENT 1 // 销售部
#define DEVELOP_DEPARTMENT 2 // 开发部
#define FINACIAL_DEPARTMENT 3 // 财务部
class Yuangong
{
public:
string name;
int age;
string tele;
double salary;
};
// 创建员工 5名
// 返回值 void
void Create_Yuangong( vector<Yuangong> &v )
{
// 名字的随机数种子
string nameseed = "ABCDE";
for(int i = 0;i<5;i++)
{
// 循环创建员工
Yuangong yg;
yg.name = "员工";
// 名字加随机数种子
yg.name += nameseed[i];
// 年龄是随机数
yg.name = rand() %30;
// 薪水是随机数
yg.salary = rand() %10000 + 10000;
// 手机号是固定的
yg.tele = "+86-88888888";
// 把这名员工放到vector中
v.push_back(yg);
}
}
// 给员工指派部门
// 入参:存放员工的vector容器, multimap<int,Yuangong>
void Set_YG_Group(vector<Yuangong>& v,multimap<int,Yuangong> & group){
for(vector<Yuangong>::iterator it = v.begin();it != v.end(); it++){
cout << "当前员工信息:" << endl;
cout << "名字:" << it->name << "年龄: " << it->age << "工资:" <<it->salary << "电话:" << it->tele << endl;
int departmentID = -1;
while(true){
cout << "请输入部门(1 销售部 2 开发部 3 财务部) : " << endl;
scanf("%d",& departmentID);
if(departmentID == SALE_DEPARTMENT){
group.insert(make_pair(SALE_DEPARTMENT,*it));
break;
}
else if(departmentID == DEVELOP_DEPARTMENT)
{
group.insert(make_pair(DEVELOP_DEPARTMENT,*it));
break;
}
else if(departmentID == FINACIAL_DEPARTMENT)
{
group.insert(make_pair(FINACIAL_DEPARTMENT,*it));
break;
}
else{
cout << "输入错误,请重新输入:" << endl;
}
}
}
}
// 打印各部门员工信息
void show_YG_Info(multimap<int,Yuangong> & group){
int departmentID = -1;
while(true){
cout << "请输入要查看的部门(1 销售部 2 开发部 3 财务部) : " << endl;
scanf("%d", &departmentID);
// 验证输入有效性
if (departmentID < 1 || departmentID > 3){
continue;
}
multimap<int,Yuangong>::iterator pos = group.find(departmentID);
int ygcount = group.count(departmentID);
int num =0;
while( pos != group.end() && num < ygcount){
cout << "姓名: " << pos->second.name << " 年龄:" << pos->second.age << " 工资:" << pos->second.salary << " 电话:" << pos->second.tele << endl;
num++;
pos++;
}
}
}
int main(void)
{
vector<Yuangong> v; // 1.存放员工的容器未分组之前
multimap<int,Yuangong> Ygroup; // 2.存放分组后的员工信息
Create_Yuangong(v); // 3.创建员工并存到容器v中
Set_YG_Group(v,Ygroup); // 4.员工分组
show_YG_Info(Ygroup); // 5.按分组显示员工信息
return 0;
}
13 容器元素深拷贝和浅拷贝问题
14 容器的共性机制
- 1. 除了queue和stack 每个容器都有迭代器
- 2. 通常STL不会抛出异常 需要使用者传入正确参数
- 3. 每个容器都提供了一个默认的构造函数和默认的拷贝构造函数
- 4. 大小相关的构造方法:
1 size() 返回容器中元素的个数
2 empty() 判断容器是否为空
15函数对象课堂基本练习
容器是值语义的
拷贝是值拷贝,push_back的时候是直接把值给原封不动拷贝了一份
执行的是原对象的拷贝构造函数
报错代码:
原因:test01执行完毕的时候执行了两次析构 释放了相同的内存区域 导致报错
解决办法:
重载拷贝构造函数:
(这里把等号操作符也重载了 因为声明变量的时候使用=调用的也是拷贝构造函数
16 stl预定义函数对象
(减法:minus)
(谓词)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <functional>
#include <string>
#include <vector>
#include <algorithm> // 欧狗瑞泽姆
using namespace std;
/*
template<class T> T plus<T> // 加法仿函数
template<class T> T minute<T> // 减法仿函数
template<class T> T multiplies<T> // 乘法仿函数
template<class T> T divides<T> // 除法仿函数
template<class T> T modules<T> // 取模仿函数
template<class T> T negate<T> // 取反仿函数
*/
void test01() {
plus<int> myplus;
int ret = myplus(10, 20);
cout << ret << endl;
plus<string> myplus2;
string s1 = "aaa";
string s2 = "bbb";
string ret2 = myplus2(s2, s1);
cout << ret2 << endl;
cout << plus<int>()(10,20) << endl;
}
// transform
void print(int v) {
cout << v << " ";
}
void test02() {
vector<int> v1, v2,v3;
for (int i = 0; i < 10;i++) {
v1.push_back(i);
v2.push_back(i + 1);
}
v3.resize(v1.size()); //
for_each(v3.begin(), v3.end(), print);
cout << endl;
cout << " -------------- " << endl;
transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), plus<int>());
for_each(v3.begin(), v3.end(), print);
cout << endl;
}
int main(void)
{
test02();
return 0;
}
C++进阶 STL(2) 第二天 一元/二元函数对象、一元/二元谓词、stack容器、queue容器、list容器(双向链表)、set容器、对组、map容器的更多相关文章
- STL算法设计理念 - 二元函数,二元谓词以及在set中的应用
demo 二元函数对象 #include <iostream> #include <cstdio> #include <vector> #include <a ...
- C++STL 预定义函数对象和函数适配器
预定义函数对象和函数适配器 预定义函数对象基本概念:标准模板库STL提前定义了很多预定义函数对象,#include <functional> 必须包含. 1使用预定义函数对象: void ...
- STL 算法中函数对象和谓词
STL 算法中函数对象和谓词 函数对象和谓词定义 函数对象: 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象.一个类对象,表现出一个函数的特 ...
- C++ STL 之 函数对象适配器
谓词是指普通函数或重载的 operator()返回值是 bool 类型的函数对象(仿函数).如果operator 接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断 ...
- STL算法中函数对象和谓词
函数对象和谓词定义 函数对象: 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象.一个类对象,表现出一个函数的特征,就是通过“对象名+(参数列 ...
- C++STL 函数对象和谓词
函数对象:重载函数调用操作符的类,其对象常称为函数对象. 函数对象属于类对象,能突破函数概念,保持类的状态 谓词: 一元函数对象:函数参数1个: 二元函数对象:函数参数2个: 一元谓词 函数参数1个, ...
- C++ STL——stack和queue
目录 一 stack容器 二 queue容器 注:原创不易,转载请务必注明原作者和出处,感谢支持! 注:内容来自某培训课程,不一定完全正确! 栈和队列作为经典的数据结构,我们再熟悉不过了.C++ ST ...
- c++的bind1st()与bind2nd() 二元算子转一元算子
bind1st()和bind2nd()是两个函数,用于将二元算子转成一元算子. 何谓二元算子? 比如< > =等等这些就是二元算子,即需要两个操作数的运算符. 何谓一元算子? 比如++ - ...
- C++进阶 STL(1) 第一天 [容器,算法,迭代器] string容器 vector容器 deque容器
课程大纲 02实现基本原理 容器,算法,迭代器 教室:容器 人:元素 教室对于楼:容器 序列式容器: 容器元素在容器中的位置是由进入容器的时间和地点来决定 序列式容器 关联式容器: 教室中 按年龄排座 ...
随机推荐
- 暑假集训D12总结
刷题 今天终于不考试= = 上午刷了一大圈线段树板子题,于是算是学会了Zkw线段树= = 下午昨天的dalao又来讲几何,然而仍然没有笔记= = 于是刷了一大圈计算几何的水题= =,并没哟啥可以写出题 ...
- 【ACM】hdu_1106_排序_201308071928
排序Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submissio ...
- 洛谷 P3004 [USACO10DEC]宝箱Treasure Chest
P3004 [USACO10DEC]宝箱Treasure Chest 题目描述 Bessie and Bonnie have found a treasure chest full of marvel ...
- EL表达式无法被解析
刚困死了,但是手上还在debug一个东西.然后就发现
- 为什么用clojure作为storm 的主要开发语言
Why you choose Clojure as the development language of Storm? Could you talk about your long practica ...
- 为大家推荐一本书《jQuery Mobile 即学即用》
这是人民邮电出版社出版的一本面向前端开发者的书. 非常喜欢书名"即学即用"这是每一个程序开发者的理想模式. 不同国家的人有不同的思维方式.这本书的作者是 [阿根廷] Maximil ...
- NYOJ_268_荷兰国旗问题
荷兰国旗问题 时间限制:3000 ms | 内存限制:65535 KB 难度:1 描写叙述 荷兰国旗有三横条块构成,自上到下的三条块颜色依次为红.白.蓝.现有若干由红.白.蓝三种颜色的条块序列.要 ...
- luogu1120 小木棍【数据加强版】 暴力剪枝
题目大意 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50.现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度.给出每段小木棍的长度,编程帮 ...
- bzoj4465: [Jsoi2013]游戏中的学问
DP 一个人要么加入一个圈,要么三个人开一圈 #include<cstdio> #include<iostream> #include<cstring> #incl ...
- Swift - 获取当前时间的时间戳(时间戳与时间互相转换)
(本文代码已升级至Swift3) 1,时间戳 时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数. 2,获取当前时间的时 ...