【STL(2)】

news2024/11/24 16:23:04

STL(2)

  • 知识点回顾
  • 函数对象
    • 函数对象理解
    • 系统的仿函数
    • 仿函数应用
  • 容器适配器
    • stack
      • deque
    • queue
    • priority_queue
  • map
    • map使用
      • 插入
      • 访问
      • 下标访问的应用:计算文件中单词的个数

知识点回顾

在STL库中存在三个容器适配器,stack - queue - priority_queue三种,其中栈和队列底层是由vector和list实现的而优先级队列是由vector实现。

函数对象

函数对象理解

class Add {
public:
	int operator()(int a,int b)const{
		return a+b;
	}
}//函数对象,仿函数,函子
int main() {
	Add add;
	int x=10,y=20,z=0;
	z=add(x,y);
	//z=add.operator()(x,y);==》z=operator()(&add,x,y);
	cout<<z<<endl;
	return 0;
}

我们不看上面Add类的时候就会觉得我们直接调用了函数,实际上是重载了函括号的重载,这就是函数对象,也叫仿函数,有时也叫函子,我们这里的举例因为两个参数,所以是二元仿函数。而怎么让其具有通用性呢?使用模板,如下:

template<class _Ty>
class Add {
public:
	_Ty operator()(const _Ty& a,const _Ty& b)const{
		return a+b;
	}
}
int main() {
	Add<int>iadd;
	Add<double>dadd;
	int x=10,y=20,z=0;
	z=Add<int>()(x,y);//z=Add<int>().operator()(x,y);
	return 0;
}

上面代码中由z=Add<int>(x,y)这一语句,代码中Add< int >是类型名加上括号是对象,也就是创建了无名对象,无名对象调用括号的重载函数。

系统的仿函数

系统中存在很多的仿函数,大于,大于等于,小于等,可以直接使用,这样也就很方便。

int main() {
	int a,==10,b=20; 
	std::greater<int> gr;
	if(x>y){}
	if(gr(x,y)) {}
	std::greater_equal<int> geq;
	if(x>=y) {}
	if(geq(x,y)) {}
}

仿函数应用

vector中没有直接的排序,需要调用系统的排序函数,而且只能是从小到大的排序,但是要是想要从大到小的呢?

int main() {
	vector<int> ar={1,4,7,6,3,2,8};
	std::sort(ar.begin(),ar.end(),std::less<int>())
	for(auto &x:ar) {
		cout<<x<<" ";
	}
	cout<<endl;
	std::sort(ar.begin(),ar.end(),std::geater<int>());
	for(auto &x:ar) {
		cout<<x<<" ";
	}
	return 0;
}

测试上面代码我们就会发现加上greater< int >()参数之后会进行从大到小的排序,这是为什么呢?
我们模拟一下排序操作和仿函数的调用:

template<class _Ty>
struct my_less {
	bool operator()(const _Ty&a,const _Ty &b) const{
		return a<b;
	}
};
template<class _Ty>
struct my_greater {
	bool operator()(const _Ty&a,const _Ty &b) const{
		return a>b;
	}
};
template<class _BI,class _Fn>
void my_sort(_BI _first,_BI _last,_Fn fn) {
	for(_BI i=_first;i!=_last;++i) {
		_BI k=i;
		for(_BI j=i+1;j!=_last;++j) {
			if(fn(*k,*j)) {k=j;}	
		}
		if(k!=i) {std::swap(*k,*i);}
	}
}
int main() {
	vector<int>ar={1,3,4,5,7,8,3,2,6,4,6,9};
	my_sort(ar.begin(),ar.end(),my_less<int>());
	for(auto &x:ar) {
		cout<<x<<" ";	
	}
	my_sort(ar.begin(),ar.end(),my_geater<int>());
	for(auto &x:ar) {
		cout<<x<<" ";	
	}
}

观察上面代码我们就可以看出排序算法实现过程中,大于小于一些运算是通过调动仿函数的比较程序来完成的,所以呢我们该百年其调用仿函数的参数就会使得其排序发生变化。系统调用也是一样的,如果不加入参数默认从小到大排序。

容器适配器

stack

栈中常用操作存在如下:
在这里插入图片描述

栈中存在操作如下:

int main() {
    stack<int> ar;
    for (int i = 9; i > 0; --i) {
        ar.emplace(i);
    }
    while (!ar.empty()) {
        int tmp = ar.top();
        ar.pop();
        cout << tmp << endl;
    }
}

栈中默认是双端队列:
一种双开口得“连续”空间得数据结构,可以在头尾两侧进行删除和插入操作,并且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素,与list相比较,空间利用率高。但是其并不是真正得连续空间,是由一段段连续得小空间拼接而成得,实际deque类似于一个动态得二维数组。但是其不适合遍历,遍历时要频繁得使用迭代器频繁得去检测其是否移动到某段小空间得边界,导致效率低下,所以呢要在不同环境使用不同得底层。

int main() {
	stack<Ptr,list<int>> is;//链栈
	stack<int,vector<int>>vis;//顺序栈
	stack<Ptr,deque<int> dis>;//双端栈
}

deque

双端队列可以通过范围for来遍历,但是我们看到的栈,优先级对列是不能用范围for遍历,因为容器适配器没有迭代器,其是随机性迭代器。

int main() {
	deque<int> deq;
	deq.push_back(12);
	deq.push_back(23);
	deq.push_front(100);
	deq.push_front(200);
	for(auto& x:deq) {
		cout<<x<<" ";
	}//200,100,12,23
}

其插入是从中间插入:在这里插入图片描述

queue

队列得构建默认用双端队列,队列是先进先出,而使用vector,vector没有头删,所以不支持。但是可以通过list来作为底层实现。

int main() {
	queue<int,deque<int>>qu;
	queue<int,list<int>> lqu;
	queue<int,vector<int>> vqu;//崩溃
}

priority_queue

优先级队列不管你插入顺序怎样,其输出顺序都是按照优先级进行输出的,这里数字大的优先级高。我们也可以通过改变参数来改变其优先级。注意双端队列只能通过vector来实现,因为只有vector是连续的空间结构,而优先级队列其实虽然叫队列但是其不满足先入先出的条件,像是数据类型中的堆,每次出队是队列中优先级最高的元素出队,而优先级可以通过元素大小进行定义。

int main() {
	priority_queue<int>pqu;
	//priority_queue<int,vector<int>,greatrt<int>> pqu;
	pqu.push(23);
	pqu.push(34);
	pqu.push(12);
	pqu.push(10);
	pqu.push(45);
	whiile(!pqu.empty()) {
		int val=pqu.top();
		pqu.pop();
		cout<<val<<endl;
	}
}

map

map使用

map的底层实现是一个红黑树。其中数据是是通过对的方式作为存放。
对的演示:

template<class T1,class T2> 
struct my_pair {
	using first_type=T1;
	using second_type=T2;
	first_type first;
	second_type second;
}
my_pair<int,string>myp{23,"xin"};
template<class _Key,class _val>
class my_map {
	using value_type=my_pair<_Key,_Val>;
	struct _rbnode {
		value_type data;
		_rbndoe* leftchild;
		_rbndoe* rightchild;
		_rbndoe* parent;
		int color;
	}
}

插入

因为结构所以插入是这样插入的:

int main() {
	std::map<std::string,int> simap;
	simap.insert(std::map<std::string,int>::value_type("xin",12));
	simap.insert(std::map<std::string,int>::value_type("lin",75));
	simap.insert(std::map<std::string,int>::value_type("wan",43));
	simap.insert(std::map<std::string,int>::value_type("axn",53));
	simap.insert(std::map<std::string,int>::value_type("cen",42));
	for(auto& x:simap) {
		cout<<x.first<<" "<<x.second<<endl;
	}
	return 0;
}

其中输出结果不是按照插入顺序插入的,会按照字符串大小顺序进行输出。当然其结果也可以通过参数改变函数对象来改变其存放顺序。
但是通常不会这么插入,因为代码过于复杂,

int main() {
	using SIMAP=std::map<std::string,int>;
	using ValType=std::map<std::string,int>::value_type;
	SIMAP simap;
	simap.insert(ValType("xin",12));
	simap.insert(ValType("lin",75));
	simap.insert(ValType("wan",43));
	simap.insert(ValType("axn",53));
	simap.insert(ValType("cen",42));
	for(auto& x:simap) {
		cout<<x.first<<" "<<x.second<<endl;
	}
	SIMAP::iterator it=simap.begin();//迭代器
	for(;it!=simap.end();++it) {
		cout<<it->first<<" "<<it->second<<endl;
	}
	return 0;
}

访问

map访问方法仍然有两种:

  • at函数查询,
  • []下标重载遍历
    两种访问方式的不同之处:
    at函数仅仅是查找元素,查找不到程序就会报错,抛出异常,而用下标查找遍历,找不到就会自动进行添加该元素,其关键码默认为0.找到就会返回其关键码。
int main() {
	using SIMAP=std::map<std::string,int>;
	using ValType=std::map<std::string,int>::value_type;
	SIMAP simap;
	simap.insert(ValType("xin",12));
	simap.insert(ValType("lin",75));
	simap.insert(ValType("wan",43));
	simap.insert(ValType("axn",53));
	simap.insert(ValType("cen",42));
	cout<<simap.at("cen")<<endl;
	cout<<simap["axn"]<<endl;
	simap["xa"];//找不到就会添加该字符串,而int值就会使用默认的缺省值0.
	std::map<int,string> ma;
	cout<<ma[1];
	return 0;
}

下标访问的应用:计算文件中单词的个数

统计文件中单词的个数和出现的频率,按出现频率输出单词:这就用到了下标访问

#define BEGIN 0
#define IN_WORD 1
#define OUT_WORD 2

int main() {
    FILE* fp = fopen("xxin.cpp", "r");
    if (nullptr == fp)exit(EXIT_FAILURE);
    int const len = 256;
    char buff[len] = {};
    int tag = BEGIN;
    int posi;
    std::map<string,int>  mp;
    while (!feof(fp)) {
        fgets(buff, len, fp);
        for (int i = 0; buff[i] != '\0'; ++i) {
            switch (tag)
            {
            case BEGIN:
                if (isalpha(buff[i])) {
                    posi = i;
                    tag = IN_WORD;
                }
                else {
                    tag = OUT_WORD;
                }
            case IN_WORD:
                if (!isalpha(buff[i])) {
                    std::string word(&buff[posi], i - posi);
                    mp[word]+=1;
                    //cout << word << endl;
                    tag = OUT_WORD;
                }
                break;
            case OUT_WORD:
                if (isalpha(buff[i])) {
                    posi = i;
                    tag = IN_WORD;
                }
            default:
                break;
            }
        }
    }
    fclose(fp);
    fp = nullptr;
    for (auto& x : mp) {
        cout << x.first << "==>" << x.second << endl;
    }
    std::multimap<int, string,greater<int>>mp1;//多重map,可以重复
    for (auto& x : mp) {
        mp1.insert(std::multimap<int, string>::value_type(x.second, x.first));
    }
    for (auto& x : mp1) {
        cout << x.first << "==>" << x.second << endl;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/599661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

西门子200系列PLC学习课程大纲(课程筹备中)

西门子200系列PLC学习课程大纲如下表所示&#xff0c;共106课&#xff0c;关注我&#xff0c;让你从菜鸟变大神。 第1课西门子200PLC概述S7-200 PLC新特性是什么第2课S7-200 PLC的CPU介绍第3课S7-200 PLC编程软件介绍第4课S7-200 PLC通信方式有哪些第5课S7-200 PLC显示面板介绍…

6.1——我在CSDN的创作纪念日

文章目录 ⭐前言⭐相遇CSDN⭐切换到编程赛道的契机&#x1f496; 好好的美工为什么切换编程赛道&#x1f496; 转换编程赛道的催化剂 ⭐写博客的目的——写给未来的自己&#x1f496; 初衷——为学习铺路&#x1f496; 博客是灯——照亮前行的路&#x1f496; 博客是路——互联…

wenet-基于预训练模型进行增量训练

1867-154075-0014 重中之重 run.sh脚本分析 wenet aishell脚本解析_weixin_43870390的博客-CSDN博客 一、准备工作 第一步&#xff1a;准备训练数据&#xff0c;拷贝到远程服务器 将准备好的数据文件0529_0531_dataset&#xff0c;上传到恒源云上的/hy-tmp/wenet/example…

数据结构与算法10:递归树、Trie树、B+树

目录 【递归树】 【Trie 树】 【B树】 【每日一练&#xff1a;最长公共前缀】 【递归树】 递归的思想是将大问题分解为小问题&#xff0c;然后再将小问题分解为更小的问题&#xff0c;直到问题的数据规模被分解得足够小&#xff0c;不用继续递归分解为止。如果把这个一层…

Effective第三版 中英 | 第2章 创建和销毁对象 | 用私有构造器或者枚举类型强化 Singleton 属性

文章目录 Effective第三版前言第二章 创建和销毁对象用私有构造器或者枚举类型强化 Singleton 属性 Effective第三版 前言 大家好&#xff0c;这里是 Rocky 编程日记 &#xff0c;喜欢后端架构及中间件源码&#xff0c;目前正在阅读 effective-java 书籍。同时也把自己学习该书…

如何在本地配置Github的项目--Python

如何在本地配置Github的项目 0. 引言1. 初步预览2. 配置环境2.1 环境已经给出2.2 环境未曾给出 3. 数据配置4. 依次调试5. 配置完成总结 0. 引言 Github上存在大量的代码。当下载下来后可能会存在疑惑&#xff1a;如何在本地配置对应的项目呢&#xff1f; 为了帮助新手解决这一…

【Android开发基础】购物车代码整理

文章目录 一、数据库设计二、Home界面三、购物车模块四、添加五、源代码 这个月总算忙完了&#xff0c;总算能够抽出时间来&#xff0c;认真写一下博客了。整理一下购物车的代码 一、数据库设计 基于SqLite简单设计一个数据存储逻辑 实体&#xff08;接收数据&#xff09; im…

【数据加密】古典密码Playfair

文章目录 一、引言1、主要任务2、分支3、密码体制分类4、攻击密码系统 二、普莱费厄体制1、构造字母表&#xff0c;设为密钥矩阵2、设立加密方法3、加密解密4、字典集合5、结果 一、引言 1、主要任务 解决信息的保密性和可认证问题&#xff0c;保证信息在生成、传递、处理、保…

Swin-Transformer详解

Swin-Transformer详解 0. 前言1. Swin-Transformer结构简介2. Swin-Transformer结构详解2.1 Patch Partition2.2 Patch Merging2.3 Swin Transformer Block2.3.1 W-MSA2.3.2 SW-MSA 3. 模型配置总结 0. 前言 Swin-Transformer是2021年微软研究院发表在ICCV上的一篇文章&#x…

数据的存储(浮点型)

目录 浮点型存储的规则 1.前面我们已经学过了整形在数据中的存储是以原码&#xff0c;反码&#xff0c;补码的形式在内存中存储的&#xff0c;那么浮点数是以什么样的形式存储的呢&#xff1f; 接下来我们通过一段代码来观察——> int main() {int n 9;float* p (float*…

String AOP的使用

面向切面编程&#xff0c;面向特定方法编程&#xff0c;以方法为对象&#xff0c;在不修改原方法的基础上&#xff0c;对方法进行操作扩展等&#xff0c;底层是通过动态代理实现的 使用开发步骤&#xff1a; 1、创建一个类&#xff0c;加上Aspect声明为一个AOP切面类&#xff…

2023 重新开始

感觉搞 IT 的日子最近都有点不太好过。 早上接到公司电话说今天是一个大日子。 为什么是大日子&#xff0c;相信所有人都是懂的。这次公司将会经历一次非常大的裁员&#xff0c;很不幸也在列表中。不过感觉这个好像也没有什么关系。 因为早就在意料之中的事情&#xff0c;经历…

c语言之结构体(初阶)

目录 1&#xff1a;结构体类型的声明 2&#xff1a;结构体初始化 3&#xff1a;结构体成员访问 4&#xff1a;结构体传参 1&#xff1a;结构体类型的声明 1&#xff1a;为啥要有结构体&#xff0c;因为当我们描述一个复杂对象的时候&#xff0c;可能平时我们的一个类型不能…

常见的五种排序

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C &#x1f525;座右铭&#xff1a;“不要等到什么都没有了&#xff0c;才下…

批量提取某音视频文案(二)

牙叔教程 简单易懂 之前写过一篇 批量提取某音视频文案 , 在之前的教程中, 我用的是微软的语音转文字功能, 今天我们换个方法, 使用 逗哥配音 的 文案提取 功能 准备工作 下载视频和音频 我在github找到的是这个仓库 https://github.com/Johnserf-Seed/TikTokDownload 注意一…

VLANIF虚接口案例实践

1&#xff09;拓扑 2&#xff09;需求&#xff1a; -所有PC能够ping通自己的网关 -实现vlan间互通&#xff0c;实现所有的PC互通 3&#xff09;配置步骤&#xff1a; 第一步&#xff1a;给pc配置IP地址 第二步&#xff1a;交换机创建vlan,做access和trunk -所有的交换机都配…

传统图形学对nerf的对比与应用落地

作者今年参加了China3DV的盛会&#xff0c;大会的发表、线下讨论、学者、工业界等等的交流着实对于Nerf有了更深的思考&#xff0c;以下是作者的抛砖引玉&#xff0c;如有不当之处敬请指出~ 传统图形学与nerf的简介&#xff1a; 传统图形学&#xff1a;显示表达几何表达方式&…

【CloudCompare教程】010:点云的裁剪功能(分段、裁剪、筛选)

本文讲解CloudCompare点云的裁剪功能(分段、裁剪、筛选)。 文章目录 一、点云的分段二、点云的裁剪三、点云的筛选一、点云的分段 加载案例点云数据,如下图所示: 选中图层点云,点击工具栏中的【分割】工具。 点击【激活线状选择】工具: 在需要裁剪的点云上绘制现状裁剪范…

使用免费的SSL证书将nginx配置的普通网站修改为HTTPS网站

一、需求说明 已经在Centos8系统中使用nginx搭建了网站;但是该网站没有实现HTTPS协议不安全;现需要将网站升级为HTTPS站点。 Linux环境对Nginx开源版源码下载、编译、安装、开机自启https://blog.csdn.net/xiaochenXIHUA/article/details/130265983?spm=1001.2014.3001.5501

chatgpt赋能python:Python交易接口简介

Python交易接口简介 Python作为一种高级编程语言&#xff0c;被广泛用于各种不同的领域&#xff0c;其中包括金融市场交易。Python交易接口提供了一种优雅而简单的方式&#xff0c;使得交易者能够方便地执行自己的交易策略。 什么是Python交易接口&#xff1f; Python交易接…